学会这招,轻松优化webpack构建性能

webpack


webpack 本质上是一个静态资源打包工具,静态资源打包是指 webpack 会将文件及其通过 importrequire 等方式引入的各项资源,处理成一个资源依赖关系图,也称为 chunk ,这些资源包括 jscssjpg, 等等。


然后将这个 chunk 内的资源分别进行处理 ,如 less 编译成 csses6 编译成 es5 ,等等。这个处理过程就是打包,最终将这些处理后的文件输出,输出的文件集合便称为 bundle


bundle 分析


学会优化 webpack 构建性能等优化,我们需要先学会如何分析 bundle,通过对产出的分析,才能有针对性的对过程进行优化。


webpack 官方提供了一个非常好用的 bundle 可视化分析工具:webpack-bundle-analyzer。这个工具会将 bundle 处理一个可视化页面,呈现出资源的依赖关系和体积大小等信息。


这个工具的使用方式也很简单,这需要在通过 npm install webpack-bundle-analyzer yarn install webpack-bundle-analyzer 安装这个插件,然后在 webpack 配置文件的 plugins 配置项中加上这一行代码:


plugins: [
new BundleAnalyzerPlugin(),
]
复制代码

运行 webpack 打包后,会自动在 http://127.0.0.1:8888/ 打开一个可视化页面:


image.png


优化小妙招


接下来我们将会结合对 bundle 的分析,进行一些优化操作。


在讲解如何优化之前,我们需要明确 chunkbundle 的关系:chunk 是一组依赖关系的集合,它不单单指一个文件,可以包含一个或多个文件。而 bundlewebpack 打包的输出结果,它可以包含一个或多个 chunk。而 webpack 打包执行时会以一个个 chunk 进行处理,前端在加载 webpack 打包的资源时,也往往是以一个 chunk 为单位加载的(无论它是一个或多个文件)。


splitChunks


从可视化界面中我们可以看到,经过 webpack 打包后我们得到一个 app.bundle.js,这是个 bundle 中包含了我们项目的所有代码以及从 node_modules 中引入的依赖,而这个 bundle 中包含了项目内的所以依赖关系,因此这个 bundle 也是我们项目中唯一一个 chunk


那么我们在加载页面时,便是加载这一整个 chunk,即需要在页面初始时加载全部的代码。


splitChunks,是由 webpack 提供的插件,通过它能够允许我们自由的配置 chunk 的生成策略,当然也包括允许我们将一个巨大的 chunk 拆分成多个 chunk


在使用 splitChunks 之前我们先介绍一个重要的配置属性 cacheGroups(如果需要,可以在官方文档 splitChunks 中了解更多):


cacheGroups 配置提取 chunk 的方案。里面每一项代表一个提取 chunk 的方案。下面是 cacheGroups 每项中特有的选项:

test选项:用来匹配要提取的 chunk 的资源路径或名称,值是正则或函数。
name选项:生成的 chunk 名称。
chunks选项,决定要提取那些内容。
priority选项:方案的优先级,值越大表示提取 chunk 时优先采用此方案,默认值为0。
enforce选项:true/false。为true时,chunk 的大小和数量限制。

接下来我们便通过实际的配置操作,将 node_modules 的内容提取成单独的 chunk,下面是我们的配置代码:


  optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
enforce: true,
priority: -3,
},
},
},
},

配置完成后,重新运行 webpack ,可以看到,node_modules 相关的依赖关系被提取成一个单独的 chunk vendors.bundle.js,最终我们得到了两个 chunkvendors.bundle.jsapp.bundle.js


image.png


那么通过这样的chunk 提取,有什么好处呢?



  1. node_modules 下往往是在项目中不会的变化的第三方依赖,我们将这些固定不变的提取成单独的 chunk 处理,webpack 便可以将这个 chunk 进行一定的缓存策略,而不需要每次都做过多的处理,减少了性能消耗。
  2. 网页加载资源时不需要一次性加载太多的资源,可以通过不同 chunk 分批次加载,从而减少首屏加载的时间。

除了这里介绍的对 node_modules 的处理外,在实际的项目中也可以根据需要对更多的资源采取这样的提取chunk 策略。



externals + CDN


通过对 bundle 的分析,我们不难发现:在我们输出的 bundlereact.development.jsreact-dom.development.js 以及 react-router.js 这三个文件特别的显眼。这表示这几个文件的体积在我们总的输出文件中占的比例特别大,那么有什么方法可以解决这些碍眼的家伙呢?


当然有! 下面将要介绍的 external + CDN 策略,便可以很好的帮助我们做到这点。


externalwebpack 的一个重要的配置项,顾名思义,它可以帮助我们将某些资源在 webpack 打包时将其剔除,不参与到资源的打包中。


external 是一个有多项 key-value 组成的对象,它的的每一项属性表示不需要经过 webpack 打包的资源,key 表示的是我们需要排除在外的依赖名称,value 则告诉 webpack,需要从 window 对象的哪个属性获取到这些被排除在外的依赖。


下面的代码就是将reactreact-domreact-router-dom 三个依赖不进行 webpack 打包的配置,它告诉 webpack,不将 reactreact-domreact-router-dom 打包进最终的输出中,需要用到这些依赖时从 window对象下的 ReactReactDOMReactRouterDOM 属性获取。


  externals: {
react: 'React',
'react-dom': 'ReactDOM',
'react-router-dom': 'ReactRouterDOM',
},
复制代码

那么这些被剔除的依赖,为什么可以从 window 对象获取到呢?答案就是 CDN !


我们将这些剔除的依赖,通过 script 标签引入对应的 CDN 资源( CDN内容分发网络,我们可以将这些静态资源存储到 CDN 网络中,以便更快的获取资源)。


这需要我们将引入这些资源的script 标签加在入口 HTML 文件中,这些加载进来的js文件,会将资源挂载在对应的 window 属性 ReactReactDOMReactRouterDOM上。


    <script src="https://cdn.staticfile.org/react/0.0.0-0c756fb-f7f79fd/cjs/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/0.0.0-0c756fb-f7f79fd/cjs/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/react-router-dom/0.0.0-experimental-ffd8c7d0/react-router-dom.development.js"></script>

接下来看下通过 external + CDN 策略处理后,我们最终输出的bundle:


image.png


react.development.jsreact-dom.development.js 以及 react-router.js 这三个文件消失了!



作者:Promise
链接:https://juejin.cn/post/7034181462106570759

0 个评论

要回复文章请先登录注册