创见博客
webpack 生产模式:是什么、为什么、怎么做
七崽爱吃小饼干2026/09/15阅读 0专栏 webpack构建基础

在 webpack 配置里,mode 是一个不起眼却极其重要的选项。它只有三个取值:development、production、none。本文聚焦 production——它是什么、为什么需要它、以及实际项目里该怎么做。

一、什么是生产模式

生产模式,就是通过 mode: 'production' 告诉 webpack:这份产物是给真实用户访问的,请在构建时尽可能做优化,而不是优先考虑构建速度。

js
module.exports = {
  mode: 'production',
};

在 webpack 4 之前,并没有 mode 这个概念,这些优化需要手动一个个开启;从 webpack 4 起,production 把一整套面向线上的优化打包成了默认行为,开箱即用。

需要说明的是,production 不是一个「环境」,而是 webpack 的一组内置优化策略的开关。它不会替你部署、不会替你配置服务器,它只影响「代码被打包成什么样」。

二、为了什么:开发与生产的目标不同

开发和生产的诉求几乎是相反的:

开发(development)生产(production)
首要目标构建快、易调试体积小、加载快
代码压缩否是
无用代码剔除否是(Tree Shaking)
Source Map详细、利于定位精简或关闭
process.env.NODE_ENV'development''production'
错误提示尽量详细尽量精简

如果生产环境也用开发配置,产物会又大又慢,还会暴露内部实现细节;反过来,用生产配置开发,每次构建又慢得让人抓狂。所以 mode 的意义,就是让同一套构建工具能服务两种截然不同的目标。

三、production 自动做了什么

设置 mode: 'production' 后,webpack 会自动启用以下能力:

  1. 代码压缩:启用 TerserPlugin,压缩混淆 JS,去掉注释和多余空白。
  2. Tree Shaking:基于 ESM 的静态分析,剔除没有被使用的导出代码(usedExports + sideEffects)。
  3. Scope Hoisting:通过 ModuleConcatenationPlugin 把多个模块合并到一个函数作用域中,减少包裹代码、提升运行速度。
  4. 定义 process.env.NODE_ENV:自动用 DefinePlugin 将其设为 'production',React、Vue 等库据此移除开发期警告代码。
  5. 确定性 ID:模块和 chunk 的 id 采用 deterministic 策略,保证多次构建结果稳定,利于长期缓存。
  6. 构建失败即停止输出:启用 NoEmitOnErrorsPlugin,有错误时不产出有问题的产物。
  7. 性能提示:对体积过大的资源给出警告(performance.hints)。

这也是为什么很多优化「你什么都没写却生效了」——它们都藏在 production 的默认配置里。

Tree Shaking 的前提

Tree Shaking 依赖 ES Module(import / export),CommonJS 因为运行时才能确定依赖,无法被有效摇树。此外,需要在 package.json 里声明 "sideEffects": false(或列出有副作用的文件),webpack 才敢安全地删除未使用模块。

json
{
  "sideEffects": ["*.css", "*.less"]
}

四、怎么做:在生产模式下的实践

1. 通过命令行或环境变量切换

json
{
  "scripts": {
    "dev": "webpack serve --mode development",
    "build": "webpack --mode production"
  }
}

2. 拆分配置文件

真实项目通常会拆成三份:公共、开发、生产,再用 webpack-merge 合并:

webpack.common.js
webpack.dev.js
webpack.prod.js
bash
npm install webpack-merge --save-dev

webpack.prod.js:

js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = merge(common, {
  mode: 'production',
  devtool: 'hidden-source-map', // 生成 Source Map 但不暴露给用户
  output: {
    filename: 'js/[name].[contenthash:8].js',
    chunkFilename: 'js/[name].[contenthash:8].chunk.js',
    clean: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css',
    }),
  ],
  optimization: {
    minimize: true,
    minimizer: ['...', new CssMinimizerPlugin()],
    splitChunks: {
      chunks: 'all',
    },
    runtimeChunk: 'single',
  },
});

几个要点:

  • [contenthash]:内容变化才改文件名,配合长期缓存。
  • devtool: 'hidden-source-map':既保留定位错误的能力,又不把源码 map 暴露给浏览器。
  • splitChunks + runtimeChunk:拆分第三方依赖和运行时,提升缓存命中率。
  • minimizer: ['...', ...]:'...' 表示保留 webpack 默认的 JS 压缩器,再追加 CSS 压缩。

3. 在代码中读取环境变量

DefinePlugin 注入的 process.env.NODE_ENV 可以在业务代码中使用,用于条件分支,这些分支在生产构建时会被静态求值并剔除:

js
if (process.env.NODE_ENV !== 'production') {
  console.log('开发期日志');
}

生产打包后,上面这段会被直接删掉。

4. 剔除开发专用配置

生产配置里不应包含:

  • devServer:这是给本地开发用的。
  • 过于详细的 devtool(如 eval-cheap-module-source-map)。
  • 开发期的 HMR、overlay 等。

5. 常见补充插件

bash
npm install compression-webpack-plugin --save-dev
js
const CompressionWebpackPlugin = require('compression-webpack-plugin');

plugins: [
  new CompressionWebpackPlugin({
    algorithm: 'gzip',
    threshold: 10240,
  }),
],

它会在构建时生成 .gz 文件,配合服务器开启 gzip 静态压缩,进一步减小传输体积。此外,webpack-bundle-analyzer 可用于分析产物体积,找出过大依赖。

五、完整配置示例

js
const path = require('path');
const { merge } = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'production',
  devtool: 'hidden-source-map',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[contenthash:8].js',
    chunkFilename: 'js/[name].[contenthash:8].chunk.js',
    assetModuleFilename: 'assets/[contenthash:8][ext]',
    publicPath: '/',
    clean: true,
  },
  module: {
    rules: [
      { test: /\.css$/i, use: [MiniCssExtractPlugin.loader, 'css-loader'] },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true,
        minifyCSS: true,
        minifyJS: true,
      },
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css',
      chunkFilename: 'css/[name].[contenthash:8].chunk.css',
    }),
    new CompressionWebpackPlugin({
      algorithm: 'gzip',
      threshold: 10240,
      test: /\.(js|css|html|svg)$/,
    }),
  ],
  optimization: {
    minimize: true,
    minimizer: ['...', new CssMinimizerPlugin()],
    splitChunks: { chunks: 'all' },
    runtimeChunk: 'single',
  },
});

小结

生产模式的核心,是用一组默认开启的优化,把代码打磨成适合线上分发的形态:

优化目的
Terser 压缩减小 JS 体积
Tree Shaking / Scope Hoisting剔除与合并代码
process.env.NODE_ENV移除开发期分支
contenthash长期缓存
CSS 抽离与压缩样式独立、减小体积
gzip 预压缩减小传输体积

做法上,记住一句话:开发要快、生产要小。用 mode 区分,用 webpack-merge 拆分,再按需补充压缩、拆分、缓存相关配置,就能得到一份可靠的线上产物。

评论
0/100