页面优化详解,如何将网页性能提升5倍?

营销圈公众号引导关注

最近对公司的一个 PC 站点做了一次整体的性能优化,由于这个系统业务复杂、依赖非常多,加载速度非常慢,优化后各个性能指标都有了显著提升,大约加载速度快了 5 倍左右。

页面优化详解,如何将网页性能提升5倍?

我在 构建、网络、资源加载、运行时、服务端、功能组织等多个方面都进行了优化,准备做一个系列,分章节给大家分享下我的优化经验。

今天,我们从优化效果最为明显的构建角度开始。

优化前

首先我们看一下在优化前站点的资源加载情况:

页面优化详解,如何将网页性能提升5倍?

可见最大的 vendor 包居然有 3MB(经过 gzip 压缩后),没有做额外配置的话,webpack 将所有的第三方依赖都打入了这个包,如果引入依赖越来越多,那么这个包就会越来越大。

另外,系统本身的逻辑打的包也达到了 600k

分析依赖关系

我们可以借助 webpack-bundle-analyzer 将打包后的内容展示为方便交互的树状图,我们可以很直观的看到有哪些比较大的模块,然后做针对性优化。

npm install --save-dev webpack-bundle-analyzer

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

页面优化详解,如何将网页性能提升5倍?

CDN 引入

这个估计大家都明白,因为打包后的产物本身也是上传到 CDN 的。但是我们要做的是将体积较大的第三方依赖单独拆出来放到 CDN 上,这样这个依赖既不会占用打包资源,也不会影响最终包体积。

如果一个依赖有直接打包压缩好的单文件 CDN 资源,例如上面图中的 g6,就可以直接使用。

按照官方文档的解释,如果我们想引用一个库,但是又不想让 webpack 打包,并且又不影响我们在程序中以 import、require 或者 window/global 全局等方式进行使用,那就可以通过配置 externals。

首先将 CDN 引入的依赖加入到 externals 中。

页面优化详解,如何将网页性能提升5倍?

然后借助 html-webpack-plugin 将 CDN 文件打入 html:

页面优化详解,如何将网页性能提升5倍?

这里有一点需要注意,在 html 中配置的 CDN 引入脚本一定要在 body 内的最底部,因为:

  • 如果放在 body 上面或 header 内,则加载会阻塞整个页面渲染。
  • 如果放在 body 外,则会在业务代码被加载之后加载,模块中使用了该模块将会报错。

拆 vendor

页面优化详解,如何将网页性能提升5倍?

某些场景下, 一个第三方依赖可能拆成了多个子依赖,例如上面的 monaco,或者没有提供可直接通过 CDN 引入的文件,我们就无法通过配置一个 CDN 文件来引入它了。

这时我们需要自己去 webpack 设置一些规则,将我们想拆出来的依赖单独打包一个 vendor。

页面优化详解,如何将网页性能提升5倍?

动态 import

将 vendor 拆分后,依赖仍然会在首屏被加载,如果依赖不在首屏使用,仍然会造成网络资源的浪费,并阻塞页面渲染,对于没必要在首屏进行加载的依赖,我们可以采用动态 import 的方式。

页面优化详解,如何将网页性能提升5倍?

例如上面这个 js-export-excel 这个依赖,自己本身有将近 500 kb,但是其只会在用户点击【导出】按钮的时候使用,我们首先在 vendor 中将其拆出来。

页面优化详解,如何将网页性能提升5倍?

使用时,将 import 的逻辑由首屏改到运行时异步加载

页面优化详解,如何将网页性能提升5倍?

这样的话,js-export-excel 这个依赖包只会在用户点击【导出】按钮时引入,首屏不再引入。

React 懒加载

类似的,对于某些第三方依赖组件,例如 monaco editor ,我们只有在很少的业务场景下才会用到,但是其本身一个包占用了 5MB 。。我们每次在打开页面时都要加载它,这太耗费性能了。

页面优化详解,如何将网页性能提升5倍?

对于一个依赖包,我们可以通过动态 import 的方式进行懒加载,但是对于一个 React 组件,直接使用动态 import 可能就不太合适了,组件渲染的运行时都是可多次触发了,不可能在每次组件渲染时都加载一次组件。

React.lazy 函数能让你像渲染常规组件一样处理动态引入组件。React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 default export 的 React 组件。

const MonacoEditor = React.lazy(() => import('react-monaco-editor'));

此代码将会在组件首次渲染时,自动导入包含 MonacoEditor 组件的包。但是直接使用React.lazy引入的组件是无法直接使用的,因为 React 无法预测组件何时被加载,直接渲染会导致页面崩溃。

在 Suspense 组件中渲染 lazy 组件,可以使用在等待加载 lazy 组件时做优雅降级(如 loading )。fallback 属性接受任何在组件加载过程中你想展示的 React 元素。你可以将 Suspense 组件置于懒加载组件之上的任何位置。你甚至可以用一个 Suspense 组件包裹多个懒加载组件。

页面优化详解,如何将网页性能提升5倍?

将所有 monaco editor 改为懒加载后,首屏已经不会加载 monaco editor。

页面优化详解,如何将网页性能提升5倍?

路由懒加载

上面 React 懒加载的方式,同样适用于路由,对于每个路由都使用懒加载的方式引入,则每个模块都会被单独打为一个 js,首屏只会加载当前模块引入的 js。

页面优化详解,如何将网页性能提升5倍?
页面优化详解,如何将网页性能提升5倍?

语言包优化

页面优化详解,如何将网页性能提升5倍?

在某些场景下,语言包会占用整个包体积的非常大一部分。实际上库本身的逻辑不会很大,moment 就是一个很好例子。

如果最开始选择日期库,那直接推荐使用 dayjs 了,如果你选择了 moment ,一定要注意把不使用的语言包过滤掉,推荐使用 ContextReplacementPlugin,它会告诉 webpack 我们会使用到哪个本地文件:

plugins: [
    new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/),
  ]

优化效果

页面优化详解,如何将网页性能提升5倍?

最终优化后,会发现模块已经被我们拆的非常均匀,并且只会在对应页面渲染时加载对应模块,这对首屏渲染速度有显著提升。

好了,这篇文章的内容营销圈就和大家分享到这里,如果大家对网络推广引流和网络创业项目感兴趣,可以添加微信:Sum8338 备注:营销圈引流学习,我拉你进直播课程学习群,每周135晚上都是有实战的推广引流技术和网络创业项目课程分享,当然是免费学!

版权声明:本站部分文章来源互联网用户自发投稿,主要目的在于分享信息,版权归原作者所有,不承担相关法律责任。如有侵权请联系我们反馈邮箱yingxiaoo@foxmail.com,我们将在7个工作日内进行处理,如若转载,请注明本文地址:https://www.yingxiaoo.com/94313.html