基于本文回答
0
评论

如何提升 Webpack 的二次构建速度(

提升 Webpack 的二次构建速度(即热更新 HMR 或重新编译的速度),核心思路是“充分利用缓存”“减少不必要的重复计算/文件解析”

以下是经过生产环境验证的最有效的优化策略,按推荐程度从高到低排列:


1. 开启 Webpack 5 原生持久化缓存(最有效)

Webpack 5 引入了强大的文件系统缓存(FileSystem Cache),能将构建过程中的模块和 Chunk 缓存到磁盘中,这是提升二次构建速度最明显的手段(通常能提升 70%~90%)

webpack.config.js 中配置:

javascript
module.exports = {
  // ...
  cache: {
    type: 'filesystem', // 使用文件系统缓存
    buildDependencies: {
      // 当配置文件发生变化时,缓存失效
      config: [__filename],
    },
    // 可选:指定缓存目录,默认在 node_modules/.cache/webpack
    name: 'development-cache', 
  },
};

:如果是 Webpack 4,需要使用 cache-loaderhard-source-webpack-plugin(但建议直接升级到 Webpack 5)。


2. 替代传统 Transpiler(用 ESBuild / SWC 替换 Babel)

Babel 解析和转换 JS/TS 的速度较慢。使用 Rust/Go 编写的编译器替代 Babel,可以极大加快二次编译的速度。

  • 使用 esbuild-loader
    javascript
    module.exports = {
      module: {
        rules: [
          {
            test: /\.[jt]sx?$/,
            loader: 'esbuild-loader',
            options: {
              loader: 'tsx', // target: 'js', 'jsx', 'ts', 'tsx'
              target: 'es2015',
            },
          },
        ],
      },
    };
  • 或者使用 swc-loader(Next.js 同款)。

3. 如果继续使用 Babel,开启 Babel 缓存

如果无法替换 Babel,务必确保开启了 babel-loader 的缓存:

javascript
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true, // 开启 babel 编译缓存
            cacheCompression: false, // 关闭压缩以节省 CPU 时间(开发环境)
          },
        },
      },
    ],
  },
};

4. 优化 Source Map 格式

Source Map 的生成方式对二次构建性能影响巨大。在开发环境中,应选择构建速度快且支持增量映射的格式。

  • 推荐开发环境配置
    javascript
    module.exports = {
      // 最佳折中方案:编译速度极快,定位到行,包含 Loader 映射
      devtool: 'eval-cheap-module-source-map', 
    };
  • 避免在开发环境使用source-mapinline-source-map 等全局重新计算的格式。

5. 精确缩小文件的检索与处理范围

不让 Webpack 去做无用功,减少递归查找的时间。

(1) 精确匹配 Loader 作用范围

确保使用 include 限制范围,或使用 exclude 排除 node_modules

javascript
{
  test: /\.js$/,
  include: path.resolve(__dirname, 'src'), // 只处理 src 下的文件
  use: ['babel-loader']
}

(2) 缩小模块决议(Resolve)范围

javascript
module.exports = {
  resolve: {
    // 1. 尽量减少后缀尝试(Webpack 从左到右匹配)
    extensions: ['.tsx', '.ts', '.js'], 
    
    // 2. 绝对路径指定 node_modules,避免递归向上查找
    modules: [path.resolve(__dirname, 'node_modules'), 'node_modules'],
    
    // 3. 使用 alias 减少路径计算
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
};

(3) 忽略大型无依赖库(module.noParse

对于没有 import/require 依赖项的大型第三方库(如 lodashchart.jsjquery),跳过 AST 语法树解析:

javascript
module.exports = {
  module: {
    noParse: /jquery|lodash/,
  },
};

6. 使用 thread-loader 进行多进程构建

如果项目非常庞大,单进程处理耗时较长,可以将耗时的 Loader(如 babel-loader)放入 Worker 线程池中并行处理。

javascript
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        use: [
          {
            loader: 'thread-loader',
            options: {
              workers: 2, // 产生的 worker 线程数
            },
          },
          'babel-loader',
        ],
      },
    ],
  },
};

注意:每个 Worker 启动都有约 600ms 开销。小型项目使用 thread-loader 反而会导致速度变慢,请根据项目体量谨慎使用。


7. 开发环境关闭不必要的产物优化

在开发环境中,应当尽可能关闭压缩、Hash 生成以及不必要的插件:

  • 关闭代码压缩:设置 mode: 'development' 默认会关闭压缩(不要手动加 TerserPlugin)。
  • 文件名不要加 Hash:开发环境输出写死文件名即可(如 [name].js),避免每次重建重新计算 Hash。
  • 避免在开发环境使用 MiniCssExtractPlugin:提取 CSS 很耗时,开发环境直接使用 style-loader 内联在 JS 中,热更新更快。

快速检查与诊断工具

如果做完上述配置后二次构建依然很慢,可以使用以下工具进行诊断:

  1. speed-measure-webpack-plugin:测量每个 Loader 和 Plugin 的消耗时间,精准定位“耗时大户”。
  2. UnusedWebpackPlugin:清理项目中未引用的残留文件。

总结推荐配置组合(开发环境)

  1. 升级到 Webpack 5
  2. 开启 cache: { type: 'filesystem' }
  3. devtool: 'eval-cheap-module-source-map'
  4. esbuild-loader 替代 babel-loader(或开启 cacheDirectory)。
  5. 正确设置 Loader 的 includeresolve.extensions

如果项目规模巨大,即便经过 Webpack 深度优化仍无法满足需求,可以考虑迁移到底层基于 Rust 的 Rspack(无缝兼容 Webpack 生态且速度极快)或使用 Vite

右滑查看面试常问