webpack详细打包配置,包含性能优化、资源处理...

发布于:2025-04-23 ⋅ 阅读:(13) ⋅ 点赞:(0)

以下是一个详细的 Webpack 5 配置示例,包含常见资源处理和性能优化方案:

const path = require('path');
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';

  return {
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: isProduction 
        ? 'js/[name].[contenthash:8].js' 
        : 'js/[name].js',
      chunkFilename: isProduction
        ? 'js/[name].[contenthash:8].chunk.js'
        : 'js/[name].chunk.js',
      assetModuleFilename: 'assets/[hash][ext][query]',
      clean: true,
    },
    mode: isProduction ? 'production' : 'development',
    devtool: isProduction ? 'source-map' : 'eval-cheap-module-source-map',
    resolve: {
      extensions: ['.js', '.jsx', '.json'],
      alias: {
        '@': path.resolve(__dirname, 'src'),
      },
      modules: ['node_modules', path.resolve(__dirname, 'src')],
    },
    module: {
      rules: [
        // JavaScript/JSX 处理
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true,
            }
          }
        },
        // CSS 处理
        {
          test: /\.css$/,
          use: [
            isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
            {
              loader: 'css-loader',
              options: {
                importLoaders: 1,
                modules: {
                  auto: true,
                  localIdentName: isProduction
                    ? '[hash:base64]'
                    : '[path][name]__[local]',
                },
              },
            },
            'postcss-loader',
          ]
        },
        // 图片处理
        {
          test: /\.(png|jpe?g|gif|webp|svg)$/,
          type: 'asset',
          parser: {
            dataUrlCondition: {
              maxSize: 10 * 1024, // 10kb 以下转 base64
            }
          }
        },
        // 字体处理
        {
          test: /\.(woff2?|eot|ttf|otf)$/,
          type: 'asset/resource',
        },
      ]
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: './public/index.html',
        minify: isProduction,
      }),
      isProduction && new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash:8].css',
        chunkFilename: 'css/[name].[contenthash:8].chunk.css',
      }),
      new webpack.ProgressPlugin(),
      new BundleAnalyzerPlugin({
        analyzerMode: 'disabled', // 不自动打开
        generateStatsFile: true, // 生成 stats.json
      }),
    ].filter(Boolean),
    optimization: {
      minimize: isProduction,
      minimizer: [
        new TerserPlugin({
          parallel: true,
          extractComments: false,
          terserOptions: {
            compress: {
              drop_console: true,
            }
          }
        }),
        new CssMinimizerPlugin(),
      ],
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all',
          },
          common: {
            minChunks: 2,
            name: 'common',
            chunks: 'all',
            priority: 10,
            reuseExistingChunk: true,
          }
        }
      },
      runtimeChunk: {
        name: entrypoint => `runtime-${entrypoint.name}`,
      },
    },
    performance: {
      maxEntrypointSize: 512 * 1024, // 512kb
      maxAssetSize: 512 * 1024,
      hints: isProduction ? 'warning' : false,
    },
    devServer: {
      static: {
        directory: path.join(__dirname, 'public'),
      },
      compress: true,
      port: 3000,
      hot: true,
      historyApiFallback: true,
      client: {
        overlay: {
          errors: true,
          warnings: false,
        },
      },
    },
  };
};

主要优化配置解析:

  1. 代码分割 (Code Splitting)

    • 通过 splitChunks 配置自动拆分第三方库(vendor)和公共代码
    • 单独提取 runtime 代码
    • 动态导入实现按需加载
  2. 缓存策略

    • 输出文件名使用 [contenthash]
    • 使用 babel-loadercacheDirectory
    • 使用 HardSourceWebpackPlugin (需单独安装)
  3. 资源优化

    • 图片小于 10KB 转为 base64
    • 自动压缩 CSS 和 JS
    • 移除 console 语句
    • Tree Shaking (生产模式自动启用)
  4. 构建性能优化

    • 使用 thread-loader 并行处理(需单独添加)
    • 缩小 loader 作用范围(exclude: /node_modules/)
    • 使用更快的 swc-loader 替代 babel(实验性)
  5. 开发体验优化

    • 热模块替换(HMR)
    • 更快的 source-map 策略
    • 进度显示
  6. 分析工具

    • 生成构建分析报告(stats.json)
    • 使用 webpack-bundle-analyzer

扩展优化建议:

  1. PWA 支持

    const WorkboxPlugin = require('workbox-webpack-plugin');
    // 添加 plugins
    new WorkboxPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true,
    })
    
  2. 预加载关键资源

    new HtmlWebpackPlugin({
      // ...
      preload: 'initial',
      prefetch: ['asyncChunk'],
    })
    
  3. CDN 加速

    output: {
      publicPath: 'https://cdn.example.com/',
    }
    
  4. DLL 加速构建

    new webpack.DllReferencePlugin({
      manifest: require('./dll/vendor-manifest.json')
    })
    
  5. 多线程处理

    {
      test: /\.js$/,
      use: [
        'thread-loader',
        'babel-loader'
      ]
    }
    

根据项目实际需求选择优化策略,建议通过以下命令分析构建结果:

npx webpack --profile --json > stats.json

然后使用 Webpack Analysewebpack-bundle-analyzer 分析打包结果。


网站公告

今日签到

点亮在社区的每一天
去签到