本文我们来学习内置在Next.js的优化技术,内容有:优化图片,使用第三方JS库,使用自定义字体,搜索引擎优化,延迟加载。
图片
Next.js有Image组件,我们应该用它来代替原生html的 image,因为Next.js的Image有自动压缩及根据屏幕的尺寸自动调整大小的特性。
我们在public目录下新建images目录,并放置一张图片coffee.jpg,该图片大小有5M。再修改app/page.tsx,Image组件的属性src调用图片的方法类似于使用对象,不用加双引号。
查看浏览器及开发工具。
切换到”网络”标签,查看图片,并停用缓存以便查看图片大小,发现只有1.3M了,图片格式变成了webp了,webp格式比jpeg更小,广泛被各浏览器支持。图片的url是 _next/image?… ,说明自动进行了优化。
这是本地图像的优化,那远端图像呢?
比如我们要显示 https://bit.ly/react-cover的图片,就需要设置src=”https://bit.ly/react-cover”,在Next.js中,显示远端的图片需要注册域,谷歌搜索”next image”,找到网页并查看说明。
https://nextjs.org/docs/pages/api-reference/components/image
修改next.config.js。
对于Next.js而言,远端的图像不像本地图像,它是不清楚尺寸大小的,所以需要手动设置高宽。
现实中,需要适配所有设备,加了特定的width和height一般不可取,可以使用Image的属性fill,同时为了不被拉伸压扁破坏宽高比,使用style={{objectFit:’cover’}},除了cover还有 contain, 不过大部分情况都用cover。如果觉得的内联css有点丑,用tailwind也是可以的,使用className=’object-cover’ 与前面是等效的。
Image有一属性是sizes。对于响应式显示,可以设置sizes=”100vw”,表示宽度占用100%的可视大小。在需要多列时,可以这样设置:sizes='(max-width:480px) 100vw, (max-width:768px) 50vw, 33vw’,表示小屏1列,中屏2列,大屏3列。注意,这些属性只是为了使next.js正确地优化图像,并不影响我们在屏幕上的显示,我们查看主页还只是一列100%宽度显示图像,我们可以添加grid组件3列,每个图像显示1/3屏幕。总之,sizes并不影响屏幕的尺寸,只是为了让next.js了解为不同的设备提供不同的图像。
quality属性表示图片质量,默认是75,可以设置的范围是1-100,我们设成80。
priority属性,默认情况下Image使用延迟加载,只有屏幕看到该图片时才加载,如果某些图片需要一开始就要加载,可以设置该priority属性。
另外我们在Image的父元素(这里是main)的className加上 “relative h-screen” 设置位置为relative,而h-screen表示高度为整个屏幕,这用于背景不错。如果图片显示在某个卡片的话,最好定义确定的高度。
使用第三方脚本
第三方脚本经常集成在我们的应用项目中,我们需要将其加到某个或多个页面上。
比如我们有一段Google分析脚本,需要加到每个网页上,我们就加在layout.tsx上,放在html标记后面,并用next.js的Script组件代替 script 标记。
由于脚本中用到dataLayer.push之类的,会有typescript报错,用{` `}包起来。Script组件有个strategy,可以有beforeInteractive、afterInteractive、lazyOnload几种。beforeInteractive表示在加载完客户端UI之后加载,一般用于比较关键的脚本;afterInteractive是默认配置;lazyOnload用于后台及低优先级页面,如聊天插件、社交媒体小部件等。
当第三方组件越来越多,就会污染layout.tsx页面,所以最好进行分离。
在Layout.tsx同级目录下新建GoogleAnalyticsScript.tsx,并将这些第三方代码复制过去。然后在Layout.tsx调用即可。
字体
我们来看看如何在Next.js中使用自定义字体。
查看Layout.tsx,从next/font/google导入Inter, Inter里可能有几十或上面种字体可以使用。如果我们不喜欢这种字体,可以更换,比如换成Roboto.
导入Roboto,它是一个函数,调用它参数提供subset, weight等得到roboto对象,然后就可以className中使用了。
打开谷歌开发工具,”网络”标签,查看字体,发现不是直接访问google的字体,而是由next.js已帮我们从谷歌下载使用了。
再来看看如何自定义字体。
先导入:import localFont from ‘next/font/local’
再在public文件夹下创建fonts目录,并放置自定义字体,比如poppins字体 poppins-regular-webfont.woff2。类似地也创建localFont的对象,属性不用subsets而是用src,注意路径使用了 .. 表示父级,也可使用 @ 表示根目录。最后也在className里调用。
我们来实现在tailwind里使用自定义字体。
添加一个属性 variable,用于设置CSS名称我们设为”–font-poppins”。并设置body的className为poppins.variable。
再到tailwind.config.ts里添加fontFamily扩展,用var获取前面定义的 –font-poppins。
接着到globals.css里设置 h1 的CSS里加上font-poppins,这样首页h1装饰的“Hello World”就能看到效果了。
搜索引擎优化
查看Layout.tsx,有metadata信息,这是被搜索引擎索引的,可以修改一下,比如作者,总体描述等,还有openGraph,可以设置社交媒体信息。
layout的metadata是被搜索引擎索引的,根据实际设置信息,比如作者,还有openGraph,里面是title,description,还有images等,用于社交媒体信息。
Layout.tsx的metadata信息会在每个页面上都有,对于特定的页面也可以设置metadata,我们在page.tsx,可以定义metadata信息,当然得注意单词不要拼错,这些都是约定的。
动态的页面,metadata也需动态生成,可以使用generateMetadata。
延迟加载
延迟加载一种策略,是指在未来某些时间需要时才加载组件或第三方组件,通常是用户交互的结果,比如当用户点击按钮或下拉到某一个点时加载。
在app/components下新建HeavyComponent.tsx,假设它有很多的复杂的js代码、HTML标记以及样式样式。并将该组件加载到首页,同时也将首页改成客户端组件。
用开发工具查看page.js,能搜索到HeavyComponent组件,说明已加载。
如果希望HeavyComponent不要马上显示出来,点按钮时才加载。修改下代码。
添加一个按钮,并设置 isVisible的状态默认为false,当点击按钮时更改为true,只有当isVisible为true时才显示HeavyComponent。
我们查看 page.js时,发现一开始还是已加载HeavyComponent组件的。原因是我们在顶部使用了静态导入。需要改成动态导入。
先导入dynamic函数,然后调用dynamic动态导入组件使用。这样之后,能看到一开始确实不会加载HeavyComponent,按了按钮之后再从服务器获取HeavyComponent组件加载。
需要说明的是,在我们的示例中,使用延迟加载没有优化,查看page.js大小就可知道。所以延迟加载只有组件很复杂时才有意义。
另外,dynamic函数除了第1个用于导入的函数作为参数外,还可以有第2个参数,它是一个对象,可以设置loading属性配置导入过程的显示组件比如显示Loading,也可以设置ssr属性为false取消服务器预渲染。
我们也可以延迟加载外部Javascript库。就拿Javascript较流行的lodash来做示例,lodash对操作数组方面很有用。
先安装:npm i lodash
为了有类型提示,再安装:npm i -D @types/lodash
完成安装后,导入lodash并在点击按钮时对数组进行排序。
但这种情况下,lodash一开始就打包在page页面中,我们需要在需要它的时候再加载,这跟前面的组件延迟加载写法有些不同。
我们在按钮点击时调用import导入lodash,它是一个Promis,所以使用await,属性default才是我们要用的lodash。调整后就是延迟加载了。
小结
本文我们学习了Next.js的相关优化知识,包括图片的优化,第三方JS库的使用,使用自定义字体,搜索引擎优化以及延迟加载。
下一篇是本系列最后一篇:部署。