Webpack性能优化笔录

优化目标

  1. 降低打包体积
  2. 提升打包速度

两个目标第一个目标优先度是大于第二个的,最理想的情况是两者取得一个平衡点。

分析工具

(1) 速度: speed-measure-webpack-plugin
(2) 体积: webpack-bundle-analyzer

降低体积

Tree shaking

Tree shaking会通过静态分析代码,没有被用到的代码会被清掉。只支持ESM模式,因为commonjs模式会存在动态引入问题,Tree shaking需要在静态编译阶段处理。

webpack 4.x production mode默认开启

Scope Hoisting

Webpack会将模块包裹成模块初始化函数,模块越多体积越大。实际上有一些只被引用一次的模块可以打包进被引用模块的初始化函数中,节省掉模块初始化函数的包裹代码。这个优化就是Scope Hoisting。

webpack 4.x production mode默认开启

清除无用的css

purgecss-webpack-plugin, 原理是记录文件里面用到的样式名称,消除没有用到的。

图片压缩

image-webpack-loader

代码分割

(1)开启optimization.splitChunks
(2)使用动态加载import非首屏页面

JS代码压缩

在optimization中选择开启minimize:true,还可以在minimizer中配置相应的压缩插件:
(1) UglyJS
(2) terser-webpack-plugin

CSS代码压缩

使用MiniCssExtractPlugin插件来压缩css文件,在Plugin配置好filenamechunkFilename之后,还要在loader中添加。要注意这个插件不能和style-loader共用:

1
2
3
4
5
6
7
8
9
{
test: /\.(sa|sc|c)ss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
}

使用动态polyfill

(1) 默认preset-env只包含了语法的编译,例如箭头函数,const,let等,没有包含的一些API和函数方法,例如fetch,Proxy,Array.prototype.includes等。可以通过配置preset-env中的useBuiltIns: "usage"启动按需引入,还需要配置browsercorejs。

(2) 可以使用polyfill service,会通过传过去的userAgent来返回对应的polyfill文件

moment优化

(1) 可以使用IgnorePlugin:

1
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)

将所有语言包排除,然后再在用到moment的地方按需引入语言包:

1
2
3
4
const moment = require('moment');
require('moment/locale/ja');

moment.locale('ja')

(2) 使用ContextReplacementPlugin:

1
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /ja|it/),

提升打包速度

使用更高版本的Webpack和node.js

Webpack 4.x比较3.x有如下的改动:

  1. 使用了更多的ES6语法优化,例如for of替换了forEach,使用了includes替换了indexOf,使用了MapSet来替换了Object
  2. 使用了md4哈希算法替换md5.
  3. loader可以直接传递AST给webpack,减少解析时间。
  4. 使用字符串方法替代正则表达式。

缩小构建的目标

通过配置resolve下面的几项:
extension - 后缀
modules - 搜索代码的文件夹
mainField - 项目的入口文件
alias - 别名
通过配置上面几项减少搜索带来的时间损耗,

babel-loader要exclude掉node_modules等不需要的模块

并行构建/压缩

(1) Terser 压缩JS代码,开启并行模式。parallel=true
(2) HappyPack / thread-loader 并行解析。

利用缓存提升二次构建速度

(1) babel-loader?cacheDirectory=true
(2) cache-loader / hard-source-webpack-plugin
(3) terser-webpack-plugin开启缓存

dll分离第三方库

通过配置dllPlugin, 打包第三方库生成 *.dll.js和manifest.json文件,项目中配置DllReferencePlugin,打包的时候不再需要编译这些第三方库。注意,如果是支持按需引入或者非共用的库就不需要使用dll打包了,例如antdlodash等。