我正在参加「掘金·启航计划」
webpack 性能优化
对于 webpack 性能优化,相信每个同学都对“打包”和“压缩”这样的事情烂熟于心,掘金也有很多相关的写得很优秀的文章。对于常见主要是以下几个方面:
-
压缩打包的结果体积
-
动态加载,减少首屏资源加载量
-
减少构建过程时间
-
优化 HTTP 资源缓存效率
压缩打包的结果体积
Webpack
的压缩代码能力,相信每个同学都见识过,甚至还把压缩成果放在了简历上:“webpack 打包后体积从 5** kb
降到 2** kb
,相比优化前节省了 38% 的代码体积”。那 webpack 是如何做到在保持一致的代码逻辑、执行流程、功能效果下,节省代码体积呢。
接下来我们从一个例子出发,假设现在有一段代码:
变量名 WEBPACK
语义很明确,看到就基本明白是干什么用的,但这对计算机并没有什么意义,我们完全可以将 WEBPACK
修改为 a
—— 从 7 个字符精简为 1 个字符,但仍保持改动前后逻辑、功能效果完全一致。并且可以看到 =
和 +
的两边都有空格,完全可以将这前后两个空格删掉。
然后继续观察代码
发现 a
、b
、c
都是 const
常量,意思是他的值被设置以后就不能修改了,这就说明 c=a+b
也是个常量,那可以把它再压缩一下:
通过上面简单的代码压缩,已经把原来的 93 个字符压缩成 20 个字符,相当于压缩了 78%
的代码体积!
同样的方法也可以对 CSS
或者 HTML
代码进行压缩。
动态加载
动态加载应该是接触最多的优化了,逻辑上,直到页面的时候才会加载当前页面的代码,因此这部分代码没必要出现在首屏资源列表中,此时我们可以使用 Webpack 的动态加载功能将该模块更改为异步导入,相信很多同学在 VUE
项目中都写过类似的代码:
动态加载是 Webpack
内置能力之一,我们不需要做任何额外配置就可以通过动态导入语句(import
、require.ensure
)轻易实现。但请注意,这一特性有时候反而会带来一些新的性能问题:一是过度使用会使产物变得过度细碎,产物文件过多,运行时 HTTP 通讯次数也会变多,在 HTTP 1.x 环境下这可能反而会降低网络性能,得不偿失;二是使用时 Webpack 需要在客户端注入一大段用于支持动态加载特性的 Runtime
压缩图片
Webpack4 还没有将 file-loader
内置,所以要写一行 use: ['file-loader']
。
但是 Webpack5 之后只需要通过 module.rules.type
属性指定 资源类型
即可。
使用 image-webpack-loader
压缩图片,并只作用在正式环境(图像压缩是一种非常耗时的操作)
module.exports = {
// ...
module: {
rules: [{
test: /\.(gif|png|jpe?g|svg)$/i,
// type 属性适用于 Webpack5,旧版本可使用 file-loader
type: "asset/resource",
use: [{
loader: 'image-webpack-loader',
options: {
// jpeg 压缩配置
mozjpeg: {
quality: 80
},
// 在生产环境下开启
disable: process.env.NODE_ENV === 'development'
}
}]
}],
},
};
持久化缓存
持久化缓存是 Webpack5 才更新的,它能够将首次构建的过程与结果数据持久化保存到本地文件系统,在下次执行构建时跳过解析、链接、编译等一系列非常消耗性能的操作。
cache.type
:缓存类型,支持'memory' | 'filesystem'
,需要设置为filesystem
才能开启持久缓存;cache.cacheDirectory
:缓存文件路径,默认为node_modules/.cache/webpack
;cache.buildDependencies
:额外的依赖文件,当这些文件内容发生变化时,缓存会完全失效而执行完整的编译构建,通常可设置为各种配置文件
将 Loader 用在刀刃上
将 loader
设置 include
或 exclude
,避免不必要的转译
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader", "eslint-loader"],
},
],
},
};
参考资料: