优化 loader 性能
进一步限制 loader 的应用范围
思路是:对于某些库,不使用 loader
例如:babel-loader 可以转换 ES6 或更高版本的语法,可是有些库本身就是用 ES5 语法书写的,不需要转换,使用 babel-loader 反而会浪费构建时间
lodash 就是这样的一个库
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 不冲突,想想看,为什么不冲突 因为在解析文件前都会进行 loader 的使用,loader 的过程在前,所以不会冲突。
缓存 loader 的结果
我们可以基于一种假设:如果某个文件内容不变,经过相同的 loader 解析后,解析后的结果也不变
于是,可以将 loader 的解析结果保存下来,让后续的解析直接使用保存的结果
cache-loader
可以实现这样的功能
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ["cache-loader", ...loaders],
},
],
},
module: {
rules: [
{
test: /\.js$/,
use: [
// 使用cache-loader
{
loader: "cache-loader",
options: {
//设置缓存结果目录
cacheDirectory: "./cache",
},
},
"babel-loader",
],
},
],
},
};
有趣的是,cache-loader
放到最前面,却能够决定后续的 loader 是否运行
实际上,loader 的运行过程中,还包含一个过程,即pitch
cache-loader
还可以实现各自自定义的配置,具体方式见文档
我们之前学习的 loader 只是下面的一段,在此之前还有 pitch 阶段,loder 会先执行 pitch,当第一个 loader 的 pitch 有返回值,那么就直接跳过当前 loader,把结果传给前面的一个 loader
function loader(source) {
return `new source`;
}
//添加pitch阶段
loader.pitch = function (filePath) {
// 可返回可不返回
// 如果返回,返回源代码
};
module.exports = loader;
为 loader 的运行开启多线程
thread-loader
会开启一个线程池,线程池中包含适量的线程
它会把后续的 loader 放到线程池的线程中运行,以提高构建效率
由于后续的 loader 会放到新的线程中,所以,后续的 loader 不能:
- 使用 webpack api 生成文件
- 无法使用自定义的 plugin api (例如
mini-css-extract-plugin
这个库的 plugin 为 webpack 的 api 做了扩展,之后这个库的 loader 又用到了扩展的这些 API) - 无法访问 webpack options
在实际的开发中,可以进行测试,来决定
thread-loader
放到什么位置
特别注意,
- 开启和管理线程需要消耗时间,在小型项目中使用
thread-loader
反而会增加构建时间 thread-loader
尽量放在开销比较大的 loader 前,放在该 loader 之后的 loader 都会在新开的线程中执行。
module.exports = {
mode: "development",
devtool: "source-map",
//
module: {
rules: [
{
test: /\.js$/,
use: [
// 使用cache-loader
{
loader: "cache-loader",
options: {
cacheDirectory: "./cache",
},
},
"thread-loader", //在这之后的loader都会被放在新的线程里
"babel-loader",
],
},
],
},
};