基于本文回答

播面 播面

文解图解播客视频,多维讲透八股文
0
评论

如何缩小 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. 进阶优化技巧

除了 includeexclude,还可以配合以下配置进一步优化:

① 结合 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'
          }
        ]
      }
    ]
  }
};

② 使用函数形式动态判断范围

includeexclude 还支持传入一个函数,可以实现更复杂的逻辑判断:

javascript
{
  test: /\.js$/,
  exclude: function (modulePath) {
    // 如果在 node_modules 中,但不是我们需要转译的包,则排除
    return /node_modules/.test(modulePath) &&
      !/node_modules\/need-to-transpile/.test(modulePath);
  },
  use: 'babel-loader'
}

最佳实践总结

  1. 优先使用 include:采用白名单思路,仅作用于 src 等业务代码目录,性能最好。
  2. 绝对路径 > 正则表达式:使用 path.resolve(__dirname, 'src') 性能优于 include: /src/
  3. 永远不要对 node_modules 整体执行 heavy loaders(如 babel-loaderts-loader),这会导致构建速度大幅下降。