在本指南中,我们将深入探讨构建生产环境网站或应用程序的一些最佳实践和实用工具。
开发和生产构建的目标差异很大。在开发环境中,我们希望有强大的源映射和具有实时重载或热模块替换功能的 localhost 服务器。在生产环境中,我们的目标转向专注于压缩后的包、更轻量的源映射和优化的资产以提高加载时间。鉴于这种逻辑上的分离,我们通常建议为每个环境编写单独的 webpack 配置。
虽然我们将分离出生产环境和开发环境特定的部分,但请注意,我们仍将维护一个“通用”配置以保持 DRY(Don't Repeat Yourself)原则。为了将这些配置合并在一起,我们将使用一个名为webpack-merge
的实用工具。有了“通用”配置,我们就无需在特定于环境的配置中重复代码。
让我们首先安装webpack-merge
并分离出我们在之前的指南中已经处理过的部分
npm install --save-dev webpack-merge
项目
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
+ const path = require('path');
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
+
+ module.exports = {
+ entry: {
+ app: './src/index.js',
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ title: 'Production',
+ }),
+ ],
+ output: {
+ filename: '[name].bundle.js',
+ path: path.resolve(__dirname, 'dist'),
+ clean: true,
+ },
+ };
webpack.dev.js
+ const { merge } = require('webpack-merge');
+ const common = require('./webpack.common.js');
+
+ module.exports = merge(common, {
+ mode: 'development',
+ devtool: 'inline-source-map',
+ devServer: {
+ static: './dist',
+ },
+ });
webpack.prod.js
+ const { merge } = require('webpack-merge');
+ const common = require('./webpack.common.js');
+
+ module.exports = merge(common, {
+ mode: 'production',
+ });
在webpack.common.js
中,我们现在已经设置了entry
和output
配置,并包含了两个环境所需的任何插件。在webpack.dev.js
中,我们将mode
设置为development
。此外,我们还添加了该环境推荐的devtool
(强大的源映射)以及我们的devServer
配置。最后,在webpack.prod.js
中,mode
设置为production
,它会加载TerserPlugin
,该插件在tree shaking指南中首次介绍。
请注意,在特定于环境的配置中使用了merge()
调用,以便在webpack.dev.js
和webpack.prod.js
中包含我们的通用配置。webpack-merge
工具提供了多种高级合并功能,但对于我们的用例,我们不需要这些功能。
现在,让我们修改 npm 脚本以使用新的配置文件。对于运行webpack-dev-server
的start
脚本,我们将使用webpack.dev.js
;对于运行webpack
以创建生产构建的build
脚本,我们将使用webpack.prod.js
package.json
{
"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": "^0.28.4",
"csv-loader": "^2.1.1",
"express": "^4.15.3",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^4.30.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0",
"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
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
});
如果您正在使用像react
这样的库,添加DefinePlugin
后,您应该会看到包大小显著减小。此外,请注意,我们任何本地的/src
代码也可以根据此变量进行判断,因此以下检查是有效的
src/index.js
import { cube } from './math.js';
+
+ if (process.env.NODE_ENV !== 'production') {
+ console.log('Looks like we are in development mode!');
+ }
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+ 在生产模式
下默认会压缩您的代码。
请注意,虽然TerserPlugin
是代码压缩的绝佳起点,并且默认使用,但还有其他选项可用
如果您决定尝试其他代码压缩插件,请确保您的新选择也能够像tree shaking指南中所述那样删除无用代码,并将其作为optimization.minimizer
提供。
我们鼓励您在生产环境中启用源映射,因为它们对于调试和运行基准测试都很有用。话虽如此,您应该选择一个构建速度相当快且推荐用于生产用途的选项(请参阅devtool
)。在本指南中,我们将在生产环境中使用source-map
选项,而不是在开发环境中使用的inline-source-map
。
webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
+ devtool: 'source-map',
});
为生产环境压缩 CSS 至关重要。请参阅生产环境压缩部分。
上述许多选项都可以设置为命令行参数。例如,optimization.minimize
可以通过--optimization-minimize
设置,mode
可以通过--mode
设置。运行npx webpack --help=verbose
查看完整的 CLI 参数列表。
虽然这些速记方法很有用,但我们建议在 webpack 配置文件中设置这些选项,以获得更多的可配置性。