知海

生产环境

webpackjsorg-main指南-教程

生产环境

在本指南中,我们将深入探讨构建生产级站点或应用程序的最佳实践和工具。

T> 本教程建立在 摇树优化开发环境 的基础上。请确保在继续之前熟悉这些指南中介绍的概念/设置。

配置分离

开发生产 构建的目标差异很大。在 开发 环境中,我们需要强大的源代码映射(source map)和带有实时重新加载或热模块替换的 localhost 服务器。而在 生产 环境中,我们的目标转向压缩 bundle、更轻量的源代码映射以及优化资源以缩短加载时间。基于这种逻辑上的分离,我们通常建议为每种环境编写独立的 webpack 配置

虽然我们会将 生产开发 特定的部分分离出来,但请注意我们仍会维护一个“公共(common)”配置,以保持代码不重复(DRY)。为了合并这些配置,我们将使用一个名为 webpack-merge 的工具。有了“公共”配置,我们就不必在特定于环境的配置中重复代码。

让我们先安装 webpack-merge,并将之前在指南中已经完成的部分拆分出来:

bash 复制代码
npm install --save-dev webpack-merge

项目结构

diff 复制代码
  webpack-demo
  ├── package.json
  ├── package-lock.json
- ├── webpack.config.js
+ ├── webpack.common.js
+ ├── webpack.dev.js
+ ├── webpack.prod.js
  ├── /dist
  ├── /src
  │   ├── index.js
  │   └── math.js
  └── /node_modules

webpack.common.js

diff 复制代码
+ import path from 'node:path';
+ import { fileURLToPath } from 'node:url';
+ import HtmlWebpackPlugin from 'html-webpack-plugin';
+
+ const __filename = fileURLToPath(import.meta.url);
+ const __dirname = path.dirname(__filename);
+
+ export default {
+   entry: {
+     app: './src/index.js',
+   },
+   plugins: [
+     new HtmlWebpackPlugin({
+       title: '生产环境',
+     }),
+   ],
+   output: {
+     filename: '[name].bundle.js',
+     path: path.resolve(__dirname, 'dist'),
+     clean: true,
+   },
+ };

webpack.dev.js

diff 复制代码
+ import { merge } from 'webpack-merge';
+ import common from './webpack.common.js';
+
+ export default merge(common, {
+   mode: 'development',
+   devtool: 'inline-source-map',
+   devServer: {
+     static: './dist',
+   },
+ });

webpack.prod.js

diff 复制代码
+ import { merge } from 'webpack-merge';
+ import common from './webpack.common.js';
+
+ export default merge(common, {
+   mode: 'production',
+ });

webpack.common.js 中,我们配置了 entryoutput,并包含了两个环境都需要的插件。在 webpack.dev.js 中,我们将 mode 设置为 development。此外,我们还为开发环境添加了推荐的 devtool(强大的源代码映射)以及 devServer 配置。最后,在 webpack.prod.js 中,mode 设置为 production,它会加载 MinimizerPlugin,该插件最早在摇树优化指南中介绍过。

请注意,在特定于环境的配置中使用了 merge() 调用,以将公共配置合并到 webpack.dev.jswebpack.prod.js 中。webpack-merge 工具提供了多种高级合并功能,但就我们的用例而言,目前还不需要用到这些。

NPM 脚本

现在,让我们修改 npm 脚本以使用新的配置文件。对于运行 webpack-dev-serverstart 脚本,我们将使用 webpack.dev.js;对于运行 webpack 创建生产构建的 build 脚本,我们将使用 webpack.prod.js

package.json

diff 复制代码
  {
    "name": "development",
    "version": "1.0.0",
    "description": "",
    "main": "src/index.js",
    "scripts": {
-     "start": "webpack serve --open",
+     "start": "webpack serve --open --config webpack.dev.js",
-     "build": "webpack"
+     "build": "webpack --config webpack.prod.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "css-loader": "^7.1.3",
      "csv-loader": "^3.0.5",
      "express": "^5.2.1",
      "html-webpack-plugin": "^5.6.6",
      "style-loader": "^4.0.0",
      "webpack": "^5.105.0",
      "webpack-cli": "^7.0.0",
      "webpack-dev-middleware": "^8.0.3",
      "webpack-dev-server": "^5.2.3",
      "webpack-merge": "^6.0.1",
      "xml-loader": "^1.2.1"
    }
  }

可以随时运行这些脚本,看看随着我们继续向 生产 配置添加内容,输出会发生什么变化。

指定模式

许多库会根据 process.env.NODE_ENV 变量来决定库中应包含哪些内容。例如,当 process.env.NODE_ENV 未设置为 'production' 时,某些库可能会添加额外的日志记录和测试以便于调试。但是,当 process.env.NODE_ENV 设置为 'production' 时,它们可能会删除或添加大量代码段,以优化实际用户的使用体验。从 webpack v4 开始,指定 mode 会自动通过 DefinePlugin 为你配置 process.env.NODE_ENV

webpack.prod.js

diff 复制代码
  import { merge } from 'webpack-merge';
  import common from './webpack.common.js';

  export default merge(common, {
    mode: 'production',
  });

T> 从技术上讲,NODE_ENV 是 Node.js 暴露给运行脚本的系统环境变量。按照惯例,服务器工具、构建脚本和客户端库使用它来确定开发与生产行为。与预期相反,process.env.NODE_ENV 在运行 webpack 时,不会在构建脚本 webpack.config.js 内部自动设置。因此,在 webpack 配置中,类似 process.env.NODE_ENV === 'production' ? '[name].[contenthash].bundle.js' : '[name].bundle.js' 的条件判断是不会生效的,除非你通过命令行显式指定 NODE_ENV=production

如果你使用像 react 这样的库,在添加 DefinePlugin 后,你应该会看到 bundle 大小显著下降。此外,请注意,我们的任何本地 /src 代码也可以利用这一点,因此以下检查是有效的:

src/index.js

diff 复制代码
  import { cube } from './math.js';
+
+ if (process.env.NODE_ENV !== 'production') {
+   console.log('看起来我们正处于开发模式!');
+ }

  function component() {
    const element = document.createElement('pre');

    element.innerHTML = [
      'Hello webpack!',
      '5 cubed is equal to ' + cube(5)
    ].join('\n\n');

    return element;
  }

  document.body.appendChild(component());

代码压缩

Webpack v4+ 在 生产模式 下默认会压缩你的代码。

请注意,虽然 MinimizerPlugin 是压缩的不错起点且被默认使用,但还有其他选择:

如果你决定尝试其他压缩插件,请确保你的新选择也能像摇树优化指南中描述的那样移除死代码,并将其作为 optimization.minimizer 提供。

源代码映射

我们鼓励你在生产环境中启用源代码映射,因为它们对于调试以及运行基准测试很有用。也就是说,你应该选择一个构建速度较快且推荐用于生产环境的选项(参见 devtool)。在本指南中,我们将在 生产 配置中使用 source-map 选项,而不是 开发 中使用的 inline-source-map

webpack.prod.js

diff 复制代码
  import { merge } from 'webpack-merge';
  import common from './webpack.common.js';

  export default merge(common, {
    mode: 'production',
+   devtool: 'source-map',
  });

T> 避免在生产环境中使用 inline-***eval-*** 选项,因为它们会增加 bundle 大小并降低整体性能。

压缩 CSS

在生产环境中压缩 CSS 至关重要。请参阅 为生产环境压缩 部分。

CLI 替代方案

上面描述的许多选项都可以通过命令行参数进行设置。例如,可以通过 --optimization-minimize 设置 optimization.minimize,通过 --mode 设置 mode。运行 npx webpack --help=verbose 查看完整的 CLI 参数列表。

虽然这些简写方法很有用,但我们建议在 webpack 配置文件中设置这些选项,以获得更好的可配置性。

帮助我们改进文档

发现翻译问题或内容错误?请告诉我们。