自从 Webpack 4 开始,生产环境构建默认使用 terseropen in new window 来压缩(minify)代码。本章来介绍下 Webpack 压缩代码的工作机制。
压缩(minify)JavaScript
这里说的压缩指的是缩小代码量,在不改变代码语义的情况下,重写代码。举个例子,比如将长的变量名重命名为短的变量名,将永远不可能到达的分支(if(false)
)删除。
在 Webpack 中,我们可以通过 optimization.minimize
和 optimization.minimizer
这两个配置项来定制代码压缩过程。
Webpack 默认使用 terser-webpack-pluginopen in new window 这个插件来压缩代码,我们来尝试修改压缩逻辑。
npm add terser-webpack-plugin --develop
webpack.parts.js
const TerserPlugin = require('terser-webpack-plugin');
exports.minifyJavaScript = () => ({
optimization: { minimizer: [new TerserPlugin()] },
});
2
3
4
5
webpack.config.js
const productionConfig = merge([
parts.minifyJavaScript(),
...
]);
2
3
4
5
6
现在执行 npm run build
可以看到构建输出与之前相同。
可以通过
terserOptions
参数来自定义压缩过程,具体可以参考插件文档。
提高代码执行性能
作为代码压缩的补充,我们可以借助一些技术手段来提高代码执行性能。比如 scope hoisting。
从 Webpack 4 开始,在生产模式中默认启用 scope hoisting. 在构建过程中,Webpack 会将所有模块都放在一个作用域中,避免了为每一个模块都生成一个闭包。scope hoisting 会降低编译速度,但是换来的是代码执行性能的提升。
压缩 HTML
如果我们通过 html-loaderopen in new window 来处理 HTML 模板的话,可以使用 posthtmlopen in new window 和 posthtml-loaderopen in new window 来对 HTML 进行预处理,然后通过 posthtml-minifieropen in new window 来压缩 HTML,同时 posthtml-minify-classnamesopen in new window 可以缩小 HTML 中样式类名称的长度。
压缩 CSS
可以使用 css-minimizer-webpack-pluginopen in new window 这个插件来压缩 CSS。MiniCssExtractPlugin
插件只会简单的合并文本,当项目中有相同样式类的时候,会产生重复代码,css-minimizer-webpack-plugin 可以解决这个问题。css-minimizer-webpack-plugin 这个插件的底层基于 cssnanoopen in new window 实现。
首先安装依赖包
npm add css-minimizer-webpack-plugin --develop
webpack.parts.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
exports.minifyCSS = ({ options }) => ({
optimization: {
minimizer: [new CssMinimizerPlugin({ minimizerOptions: options })],
},
});
2
3
4
5
6
7
webpack.config.js
const productionConfig = merge([
parts.minifyJavaScript(),
parts.minifyCSS({ options: { preset: ["default"] } }),
...
]);
2
3
4
5
此时执行 npm run build
, 可以看到输出的 css 文件变小了。
⬡ webpack: Build Finished
⬡ webpack: assets by path *.js 129 KiB
asset 935.js 126 KiB [emitted] [minimized] (id hint: vendors) 2 related assets
asset main.js 3.28 KiB [emitted] [minimized] (name: main) 1 related asset
asset 958.js 183 bytes [emitted] [minimized] 1 related asset
asset main.css 1.37 KiB [emitted] [minimized] (name: main)
asset index.html 259 bytes [emitted]
Entrypoint main 131 KiB (182 KiB) = 935.js 126 KiB main.css 1.37 KiB main.js 3.28 KiB 2 auxiliary assets
runtime modules 7.81 KiB 10 modules
orphan modules 465 bytes [orphan] 2 modules
code generated modules 133 KiB (javascript) 4.18 MiB (css/mini-extract) [code generated]
modules by path ./node_modules/ 133 KiB
modules by path ./node_modules/react/ 6.48 KiB 2 modules
modules by path ./node_modules/react-dom/ 119 KiB 2 modules
modules by path ./node_modules/scheduler/ 4.91 KiB
./node_modules/scheduler/index.js 198 bytes [built] [code generated]
./node_modules/scheduler/cjs/scheduler.production.min.js 4.72 KiB [built] [code generated]
./node_modules/object-assign/index.js 2.06 KiB [built] [code generated]
modules by path ./src/ 633 bytes (javascript) 4.18 MiB (css/mini-extract)
./src/index.js + 2 modules 600 bytes [built] [code generated]
css ./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[3]!./src/main.css 4.18 MiB [code generated]
./src/lazy.js 33 bytes [built] [code generated]
webpack 5.11.1 compiled successfully in 18304 ms
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
压缩输出的 Bundle
可以通过 gzip 或者 brotli 等压缩结束进一步压缩输出的文件大小。压缩后的代码会增加在浏览器端的解析时间,但是可以大大减少网络带宽占用。
在 Webpack 可以使用 compression-webpack-pluginopen in new window 这个插件来压缩代码。
混淆(Obfuscating)输出
obfuscator-loaderopen in new window 可以用来对代码进行混淆,是的代码在浏览器端不可读。
总结
代码压缩(minify) 可以用一种安全的转换方法来缩小代码量。
Webpack 在生产模式中,默认使用 Terser 来压缩代码。
除了压缩 JavaScript,我们还可以通过一些插件和 loader 来压缩 CSS 和 HTML。
关注微信公众号,获取最新推送~
加微信,深入交流~