电商网站性能优化 - Part Ⅱ
之前主要在缓存方面对 Website 进行了优化,优化 1。主要解决了第二次及以上访问 app 的速度问题,但是对于用户第一次访问还是会慢一些,整个站点的 Web Vitals 也不是很好。
这是优化前的得分:
所以,决定通过一些分析工具对整个站点做一个全面的性能分析,再对症下药。
那么,有哪些好用的性能分析工具?
- PageSpeed Insights
这是 Google 的在线性能分析工具,可以提供你站点近 28 天的性能数据,包括 core web vitals(FCP,CLS,LCP 等)。 - Chrome lighthouse
谷歌浏览器本地自带的性能分析工具,可以在本地对你的应用进行“跑分”。
以上工具跑完都会得出上图的一份性能报告,报告的内容可以叫做Web vitals,这是 Google 制定的用来衡量 web page 性能的 guideline 。
比如,guideline 中给出了 LCP 应该在站点开始加载后 2.5s 内完成,才对用户比较友好。
另外,我们还用到了一个工具 webpack-bundle-analyzer,用来分析 bundle 的大小以及组成。
在next.config.js
中,修改 webpack 的配置,添加这个插件,插件会在执行yarn analyze
时执行。
if (process.env.ANALYZE === "true") {
try {
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: options.isServer ? "../analyze/server.html" : "./analyze/client.html",
})
);
} catch (e) {
console.log("bundling error", e);
}
}
开始行动
打开 PageSpeed Inside 跑一遍站点,等到一个优化前的性能报告。如下:
总得分只有 7,其它指标也基本是飘红的。
其中CLS
分数过大主要是因为页面有元素发生了偏移,主要是两个注册按钮需要再判断用户有没登陆后才显示,然后又没有为其预留空间,就会导致按钮出现的时候整个页面会整体往下移一下,页面发生了位移,这个比较好解决,只要给两个注册按钮预留空间就可以了。
再看下效果:
其次,FCP 与 LCP 的分数分别达到了3.0s
与6.0s
,与 Good level 的1.8s
和2.5s
还是有一定的差距。
可以仔细揣摩下这两个指标的具体含义和计算方式,FCP(First-Contentful-Paint),简单的来讲就是用户从打开你的站点到看到网站的内容,总共等待了多长时间,如果是 1.8s 内则认为是一个好的体验,不一定要看到全部内容,部分文本,图像,甚至背景图即可。
大家看到可以作弊的地方了嘛 👀,是不是可以搞个小小的隐晦点的 svg?站点加载完再删掉?当然这样没有意义。
LCP Largest-Contentful-Paint,简单来讲就是页面中最大的那个元素
的渲染时间,可以是 text block 或 image block。
Example
对于我们站点来说,LCP 就是首页的 banner 图的渲染时间。
性能报告也有指出哪些地方是可以做优化的
在Opportunity
模块
- “Reduce initial server response time” 影响到 FCP、LCP 指标
- “Reduce unused JavaScript”会影响 LCP 指标
我们的应用是直接 hot start 跑在 AWS 的 EC2 上,没有使用到 CDN,另外首页的内容用 Builder.io
进行管理,需要去 builder.io 拉取资讯来做 SSR。整体下来效果不是很好。
还是需要 CDN 加持。
做了个测试:
使用 CDN 之前:
使用 CDN 之后:
可以看到,使用 CDN 资源的响应时间快了五倍多。所以,后续是有计划给站点的静态资源加上 CDN。
对于 Reduce unused JavaScript,简单的理解就是减少页面所有 JS 资源的 bundle 体积。这样可以较少传输、解析与执行的时间。Next.js 的每个页面都会依赖一些公共的 thunk。
比如:
这是 Next.js 打包后的产物,其中First Load JS shared by All
指每个页面都需要依赖这些资源,都要去加载这些资源。而我们这些资源大小足足有600+kB
,
特别是 app.js。
这时就需要用到前面提到的 webpack-bundle-analyzer 去查看每个 bundle 的组成。后面发现,app.js 里包含了很多并不通用的资源
,这些都是因为没有 Tree-Sharking 而被包含了进来,应该是因为我们使用的是 Next.js 12 版本,可能是使用的 webpack 4? 所以没有默认开启 Tree-Sharking。
所以,通过开启 Tree-Sharking 解决,在 package.json 里指定 Side effect
"sideEffects": [
"./src/components/templates/Builder/gfm.tsx"
],
开启 sideEffects 需要你对项目特别了解,需要将那些虽然没有被引用到但是实际有在使用的资源列出来,避免被 sharking 掉,而产生 bug。
具体可翻阅文档:https://webpack.js.org/guides/tree-shaking/。
另外,对几个依赖包进行了优化,比如使用lodash-esm
替换lodash
,减少 buidler.io SDK 体积等。
另外,我觉得还有一个很关键的点,就是使用Lazy load
。 比如,登录弹窗等,就可以等用户点击了再去加载,在 Next.js 中可以方便的使用 Dynamic API 轻松实现Lazy load
。
最后First Load JS shared by All
的体积减少了一半,只有 300+KB,这样每个页面需要加载的所有资源也会减少了,但依然还是飘红,有待进一步优化。
最后得到的分数:
FCP LCP 指标都得到了提升,然而还不是特别理想,还是有更多的机会去提高它。
后续的计划:
- 上 CDN
- 等等
有兴趣的同学可以一起探讨!