Webpack 5 配置优化

2026-06-22 · 6 阅读 · 562字
JavaScript前端工程化

Webpack 5 配置优化

为什么需要优化

Webpack 是现代前端最常用的构建工具之一。随着项目规模增长,构建时间和产出质量成为关注重点。本文将介绍从开发到生产的全方位优化策略。

开发体验优化

缩小文件搜索范围

// webpack.config.js
module.exports = {
  resolve: {
    // 只查找这些扩展名
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
    // 指定模块搜索目录
    modules: [path.resolve(__dirname, 'src'), 'node_modules'],
    // 别名,减少查找路径
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
};

模块解析优化

module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        // 只处理 src 目录
        include: path.resolve(__dirname, 'src'),
        // 排除 node_modules
        exclude: /node_modules/,
        use: 'babel-loader',
      },
    ],
  },
};

缓存

// 持久化缓存(Webpack 5 内置)
module.exports = {
  cache: {
    type: 'filesystem', // 文件系统缓存
    cacheDirectory: path.resolve(__dirname, '.temp_cache'),
    buildDependencies: {
      config: [__filename], // 配置变化时失效
    },
  },
};

构建速度优化

多进程构建

// 安装 thread-loader
module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: [
          'thread-loader', // 放在第一位
          'babel-loader',
        ],
      },
    ],
  },
};

使用更快的 loader

// esbuild-loader 替代 babel-loader
const { EsbuildPlugin } = require('esbuild-loader');

module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'esbuild-loader',
        options: {
          loader: 'tsx',
          target: 'es2020',
        },
      },
    ],
  },
  optimization: {
    minimizer: [
      new EsbuildPlugin({
        target: 'es2020',
        css: true,
      }),
    ],
  },
};

产出优化

代码分割

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
          priority: 10,
        },
        common: {
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

动态导入

// React.lazy + Suspense 自动代码分割
const LazyPage = React.lazy(() => import('./pages/LazyPage'));

// 或者 Webpack 的 import()
function Page() {
  const [module, setModule] = useState(null);
  useEffect(() => {
    import('./heavy-module').then((mod) => setModule(mod.default));
  }, []);
}

压缩优化

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      '...', // 保留默认 JS 压缩
      new CssMinimizerPlugin(), // CSS 压缩
    ],
  },
};

Tree Shaking

// package.json 中标记 side effects
{
  "sideEffects": [
    "*.css",
    "*.global.js"
  ]
}
// Webpack 配置确保 production 模式启用 tree shaking
module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true,
    sideEffects: true,
  },
};

图片和资源优化

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif|svg)$/,
        type: 'asset', // 自动选择 inline 或 resource
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024, // 8KB 以下转为 base64
          },
        },
        generator: {
          filename: 'images/[name].[contenthash:8][ext]',
        },
      },
      {
        test: /\.(woff2?|eot|ttf)$/,
        type: 'asset/resource',
        generator: {
          filename: 'fonts/[name].[contenthash:8][ext]',
        },
      },
    ],
  },
};

模块联邦(Module Federation)

Webpack 5 的模块联邦可以实现微前端架构:

const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'app1',
      filename: 'remoteEntry.js',
      exposes: {
        './Header': './src/components/Header',
        './Footer': './src/components/Footer',
      },
      shared: {
        react: { singleton: true },
        'react-dom': { singleton: true },
      },
    }),
  ],
};

生产配置完整示例

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  mode: 'production',
  entry: './src/index.tsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[contenthash:8].js',
    clean: true,
  },
  cache: { type: 'filesystem' },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    alias: { '@': path.resolve(__dirname, 'src') },
  },
  module: {
    rules: [
      { test: /\.tsx?$/, loader: 'esbuild-loader', options: { loader: 'tsx' } },
      { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'] },
      { test: /\.(png|jpg)$/, type: 'asset', parser: { dataUrlCondition: { maxSize: 8 * 1024 } } },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html' }),
    new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' }),
  ],
  optimization: {
    splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors' } } },
  },
};

总结

优化没有银弹,需要根据项目实际情况选择策略。开发阶段关注构建速度,生产阶段关注产出质量。建议从性能分析(webpack-bundle-analyzer)入手,找到瓶颈后再针对性优化。