Skip to content
On this page

Webpack 生产环境配置

生产环境配置专注于代码优化、性能提升和资源压缩,确保应用程序在生产环境中具有最佳性能。

生产环境基础配置

基础生产配置

javascript
module.exports = {
  mode: 'production',                      // 生产模式
  devtool: 'source-map',                   // 生产环境使用源映射便于调试
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',   // 使用内容哈希实现长期缓存
    chunkFilename: '[name].[contenthash].chunk.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',                       // 或者使用 CDN 路径
    clean: true                           // 构建前清理输出目录
  }
};

优化配置

javascript
module.exports = {
  mode: 'production',
  optimization: {
    minimize: true,                        // 启用代码压缩
    minimizer: [
      // JavaScript 压缩
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,            // 删除 console
            drop_debugger: true,           // 删除 debugger
            pure_funcs: ['console.log']    // 删除特定函数调用
          },
          mangle: true,                    // 变量名混淆
          format: {
            comments: false                // 删除注释
          }
        },
        extractComments: false
      })
    ],
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          chunks: 'all'
        },
        common: {
          name: 'common',
          minChunks: 2,
          priority: 5,
          chunks: 'all',
          enforce: true
        }
      }
    },
    runtimeChunk: {
      name: 'runtime'
    }
  }
};

代码压缩与优化

JavaScript 压缩

javascript
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true,                    // 并行压缩
        extractComments: 'all',            // 提取注释到单独文件
        terserOptions: {
          compress: {
            // 压缩选项
            drop_console: true,            // 删除 console 语句
            drop_debugger: true,           // 删除 debugger 语句
            pure_funcs: [                  // 删除纯函数调用
              'console.debug',
              'console.info'
            ],
            passes: 2,                     // 压缩次数
            reduce_funcs: false            // 不减少函数
          },
          mangle: {
            reserved: ['$', 'jQuery']      // 保留特定名称不被混淆
          },
          format: {
            comments: false                // 删除所有注释
          }
        }
      })
    ]
  }
};

CSS 压缩

javascript
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new CssMinimizerPlugin({
        test: /\.css$/g,
        parallel: true,                    // 并行处理
        minimizerOptions: {
          preset: [
            'default',
            {
              discardComments: { removeAll: true },
              normalizeWhitespace: true
            }
          ]
        }
      })
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css'
    })
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,    // 提取 CSS 而不是注入到 JS 中
          'css-loader'
        ]
      }
    ]
  }
};

资源优化

图片优化

javascript
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset',                     // Webpack 5 资源模块
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024             // 8kb 以下转为 base64
          }
        },
        generator: {
          filename: 'images/[name].[contenthash:8][ext]'
        }
      },
      // 或者使用 imagemin 进行图片压缩
      {
        test: /\.(jpe?g|png|gif)$/i,
        use: [
          {
            loader: 'image-webpack-loader',
            options: {
              mozjpeg: {
                progressive: true,
                quality: 65
              },
              optipng: {
                enabled: false
              },
              pngquant: {
                quality: [0.65, 0.90],
                speed: 4
              },
              gifsicle: {
                interlaced: false
              }
            }
          }
        ]
      }
    ]
  }
};

字体优化

javascript
module.exports = {
  module: {
    rules: [
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'fonts/[name].[contenthash:8][ext]'
        }
      }
    ]
  }
};

代码分割策略

高级代码分割

javascript
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      maxInitialRequests: 10,              // 最大初始化请求数
      maxAsyncRequests: 10,                // 最大异步请求数
      cacheGroups: {
        // 第三方库
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          chunks: 'initial',
          maxSize: 244000                  // 最大 244kb
        },
        
        // React 生态
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: 'react',
          priority: 20,
          chunks: 'initial'
        },
        
        // 公共代码
        common: {
          name: 'common',
          minChunks: 2,                    // 至少被 2 个 chunk 使用
          priority: 5,
          chunks: 'initial',
          minSize: 0                       // 最小大小为 0
        },
        
        // 样式文件
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true                    // 强制创建 chunk
        }
      }
    }
  }
};

动态导入优化

javascript
// 在应用代码中使用动态导入
// src/App.js
const Home = lazy(() => import('./components/Home'));
const About = lazy(() => import('./components/About'));

// Webpack 配置
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        // 动态导入的代码
        async: {
          chunks: 'async',
          minChunks: 1,
          name(module) {
            // 为动态导入创建有意义的名称
            const path = require('path');
            const fileName = module
              .identifier()
              .split('node_modules')[1]
              .replace(/^[/\\]+/, '')
              .replace(/[/\\]+/g, '-')
              .split('.')[0];
            return `async-${fileName}`;
          }
        }
      }
    }
  }
};

缓存策略

长期缓存配置

javascript
module.exports = {
  optimization: {
    moduleIds: 'deterministic',            // 确定性模块 ID
    chunkIds: 'deterministic',             // 确定性 chunk ID
    runtimeChunk: 'single',                // 单独的运行时 chunk
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  },
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].chunk.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  }
};

服务端缓存配置

javascript
// 结合服务器配置实现缓存
module.exports = {
  output: {
    filename: '[name].[contenthash:8].js',
    chunkFilename: '[name].[contenthash:8].chunk.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'https://cdn.example.com/assets/'  // CDN 路径
  },
  plugins: [
    // 生成资源映射文件
    new WebpackManifestPlugin(),
    
    // 生成子资源完整性 (SRI)
    new SriPlugin({
      hashFuncNames: ['sha256', 'sha384']
    })
  ]
};

生产环境安全配置

安全优化

javascript
module.exports = {
  optimization: {
    sideEffects: false,                    // 正确标记副作用
    providedExports: true,                 // 提供导出信息
    usedExports: true,                     // 标记使用的导出(Tree Shaking)
    concatenateModules: true               // 模块串联(Scope Hoisting)
  },
  stats: {
    all: false,
    modules: false,                        // 不显示模块信息
    maxModules: 0,
    errors: true,
    warnings: true
  }
};

环境变量安全

javascript
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
      'process.env.API_URL': JSON.stringify(process.env.PROD_API_URL),
      // 不要在生产环境中暴露敏感信息
      '__DEV__': JSON.stringify(false),
      '__PROD__': JSON.stringify(true)
    })
  ]
};

性能监控与分析

Bundle 分析

javascript
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    // 生产环境分析(可选)
    process.env.ANALYZE && new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      openAnalyzer: false,
      reportFilename: 'bundle-report.html'
    })
  ].filter(Boolean)                       // 过滤掉 undefined
};

性能预算

javascript
module.exports = {
  performance: {
    maxAssetSize: 250000,                  // 单个资源最大 250kb
    maxEntrypointSize: 250000,             // 入口点最大 250kb
    hints: 'warning'                       // 性能警告
  }
};

生产环境完整配置示例

javascript
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  mode: 'production',
  devtool: 'source-map',                   // 生产环境源映射
  entry: {
    app: './src/index.js'
  },
  
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].chunk.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
    clean: true
  },
  
  optimization: {
    minimize: true,
    minimizer: [
      // JavaScript 压缩
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,
            drop_debugger: true
          },
          format: {
            comments: false
          }
        },
        extractComments: false
      }),
      
      // CSS 压缩
      new CssMinimizerPlugin()
    ],
    
    // 代码分割
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          chunks: 'all'
        }
      }
    },
    
    // 运行时代码分离
    runtimeChunk: 'single',
    
    // 模块 ID 优化
    moduleIds: 'deterministic',
    chunkIds: 'deterministic'
  },
  
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env', {
                useBuiltIns: 'usage',
                corejs: 3
              }]
            ]
          }
        }
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader'
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024
          }
        },
        generator: {
          filename: 'images/[name].[contenthash:8][ext]'
        }
      }
    ]
  },
  
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/index.html',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true
      }
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css'
    })
  ],
  
  performance: {
    maxAssetSize: 250000,
    maxEntrypointSize: 250000,
    hints: 'warning'
  }
};

小结

生产环境配置的重点在于优化性能、减少文件大小和提高加载速度。关键配置包括代码压缩、资源优化、缓存策略、代码分割等。合理的生产环境配置能够显著提升用户体验和应用性能。