在 Webpack 构建过程中,Loader 是一个非常重要的部分,用于处理和转换各种类型的模块。通过优化 Loader 的性能,可以显著提高构建速度,提升开发效率。以下是几种常见的优化方法:
1. 进一步限制 Loader 的应用范围
1.1 排除不需要转换的模块
有些库本身就是用 ES5 语法书写的,不需要经过 Babel 转换,使用 babel-loader
反而会浪费构建时间。例如,lodash
是一个在 ES5 之前出现的库,使用的是 ES3 语法。
通过 module.rule.exclude
或 module.rule.include
,可以排除或仅包含需要应用 Loader 的场景。
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /lodash/,
use: "babel-loader"
}
]
}
};
如果更激进一些,可以排除掉 node_modules
目录中的模块,或仅转换 src
目录的模块。
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
// 或
// include: /src/,
use: "babel-loader"
}
]
}
};
这种做法是对 Loader 的范围进行进一步的限制,与 noParse
不冲突,因为 noParse
主要是针对整个模块的解析,而 exclude
和 include
是针对特定规则的。
2. 缓存 Loader 的结果
2.1 使用 cache-loader
我们可以基于一种假设:如果某个文件内容不变,经过相同的 Loader 解析后,解析后的结果也不变。因此,可以将 Loader 的解析结果保存下来,让后续的解析直接使用保存的结果。
cache-loader
可以实现这样的功能。
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ['cache-loader', 'babel-loader']
}
]
}
};
有趣的是,cache-loader
放到最前面,却能够决定后续的loader
是否运行
实际上,loader
的运行过程中,还包含一个过程,即pitch
cache-loader
还可以实现自定义的配置,具体方式见文档。
3. 为 Loader 的运行开启多线程
3.1 使用 thread-loader
thread-loader
会开启一个线程池,线程池中包含适量的线程。它会把后续的 Loader 放到线程池的线程中运行,以提高构建效率。
由于后续的 Loader 会放到新的线程中,所以,后续的 Loader 不能:
- 使用 Webpack API 生成文件
- 无法使用自定义的 Plugin API
- 无法访问 Webpack 选项
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ['thread-loader', 'babel-loader']
}
]
}
};
在实际的开发中,可以进行测试,来决定 thread-loader
放到什么位置。特别注意,开启和管理线程需要消耗时间,在小型项目中使用 thread-loader
反而会增加构建时间。
4. 总结
通过以上几种方法,可以显著优化 Loader 的性能,提高构建速度。具体选择哪种方法,需要根据项目的实际情况进行权衡。