如何缩小 Webpack 的 Loader 处理范围(如 include / exclude)?
在 Webpack 中,缩小 Loader 的处理范围是提高构建速度(Build Performance)最有效的方法之一。默认情况下,如果不做限制,Loader 会遍历匹配到的所有文件(包括庞大的 node_modules),这会导致极大的性能浪费。
以下是缩小 Loader 处理范围的具体方法和最佳实践:
1. 使用 include 明确指定处理目录(推荐)
include 采用白名单机制,只让 Loader 处理指定目录下的文件。这是最推荐的方式。
提示:建议配合
path.resolve使用绝对路径,这比正则表达式匹配速度更快。
javascript
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
// 只处理 src 目录下的 js 文件
include: path.resolve(__dirname, 'src'),
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
};
如果要包含多个目录,可以传入一个数组:
javascript
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'components')
]
2. 使用 exclude 排除不需要处理的目录
exclude 采用黑名单机制,排除不需要处理的文件。最常见的用法就是排除 node_modules。
javascript
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
// 排除 node_modules 目录
exclude: path.resolve(__dirname, 'node_modules'),
// 或者使用正则:exclude: /node_modules/,
use: 'babel-loader'
}
]
}
};
3. 特殊场景:排除 node_modules,但编译其中某几个特定依赖包
有些第三方 npm 包发布的是 ES6+ 代码,需要用 Babel 转译。此时你可以组合使用 include 或在 exclude 中使用否定正则。
方法 A:使用 include 包含该特定包(推荐,更清晰)
javascript
include: [
path.resolve(__dirname, 'src'),
// 显式包含需要 Babel 转译的第三方库
path.resolve(__dirname, 'node_modules/some-es6-library')
]
方法 B:在 exclude 中使用正则负向预查(Negative Lookahead)
javascript
exclude: /node_modules\/(?!(some-es6-library|another-es6-library)\/)/
4. 进阶优化技巧
除了 include 和 exclude,还可以配合以下配置进一步优化:
① 结合 oneOf 避免无意义的规则遍历
默认情况下,每一个文件都会遍历 rules 里的所有 Loader。使用 oneOf 可以在匹配到第一个 Loader 后立即跳出遍历。
javascript
module.exports = {
module: {
rules: [
{
// 只要匹配到了 oneOf 里的某一个,就不再往下匹配
oneOf: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
use: 'babel-loader'
}
]
}
]
}
};
② 使用函数形式动态判断范围
include 和 exclude 还支持传入一个函数,可以实现更复杂的逻辑判断:
javascript
{
test: /\.js$/,
exclude: function (modulePath) {
// 如果在 node_modules 中,但不是我们需要转译的包,则排除
return /node_modules/.test(modulePath) &&
!/node_modules\/need-to-transpile/.test(modulePath);
},
use: 'babel-loader'
}
最佳实践总结
- 优先使用
include:采用白名单思路,仅作用于src等业务代码目录,性能最好。 - 绝对路径 > 正则表达式:使用
path.resolve(__dirname, 'src')性能优于include: /src/。 - 永远不要对
node_modules整体执行 heavy loaders(如babel-loader、ts-loader),这会导致构建速度大幅下降。