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

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

javascript 复制代码
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 支持

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

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

    javascript 复制代码
    output: {
      publicPath: 'https://cdn.example.com/',
    }
  4. DLL 加速构建

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

    javascript 复制代码
    {
      test: /\.js$/,
      use: [
        'thread-loader',
        'babel-loader'
      ]
    }

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

bash 复制代码
npx webpack --profile --json > stats.json

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

相关推荐
Pedantic16 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘16 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆16 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师17 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆17 小时前
VSCode自动格式化三要素
前端
爱勇宝18 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen18 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user205855615181321 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode21 小时前
Redis 在生产项目的使用
前端·后端