在Webpack4.0中,通过mode指定环境,用于配置运行环境。
mode的值可以为development,表示的是开发模式,或者是production,表示的是生产模式。
webpack 会将 production 作为 mode 的默认值去设置。
development(开发环境) 和 production(生产环境) 这两个环境下的构建目标存在着巨大差异。
在开发环境中,需要:强大的 source map 和一个有着 live reloading(实时重新加载) 或 hot module replacement(热模块替换) 能力的 localhost server。
生产环境中:关注点在于压缩 bundle、更轻量的 source map、资源优化等,通过这些优化方式改善加载时间。
通常,建议为每个环境编写彼此独立的 webpack 配置(遵循逻辑分离)。
webpack-merge
为了将这些不同环境的配置合并在一起,需要使用一个名为 webpack-merge
的工具。
此工具会引用 “common” 配置,因此,不必再在环境特定(environment-specific)的配置中编写重复代码。
安装 webpack-merge
:
npm install --save-dev webpack-merge
安装完成:
此时项目结构:
|- package.json
|- package-lock.json
|- webpack.common.js
|- webpack.dev.js
|- webpack.prod.js
|- /dist
|- /src
|- index.js
|- math.js
|- /node_modules
webpack.common.js:
遵循不重复原则(Don’t repeat yourself - DRY),通常保留一个 “common(通用)” 配置。
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
(强大的 source map)和 devServer
配置。
在 webpack.prod.js
中,将 mode
设置为 production
,其中会引入 TerserPlugin
。
webpack-merge
工具提供了各种 merge(合并) 高级功能。注意,在环境特定的配置中使用 merge()
功能,可以很方便地引用 webpack.dev.js
和 webpack.prod.js
中公用的 common 配置。
NPM Scripts
现在,修改 scripts
让其 重新指向到新配置。
让 npm start
script 中 webpack-dev-server
, 使用 webpack.dev.js
, 而让 npm run build
script 使用 webpack.prod.js
:
修改package.json:
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"start": "webpack serve --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"express": "^4.17.3",
"html-webpack-plugin": "^5.5.0",
"ts-loader": "^9.2.6",
"typescript": "^4.5.5",
"webpack": "^5.69.0",
"webpack-cli": "^4.9.2",
"webpack-dev-middleware": "^5.3.1",
"webpack-dev-server": "^4.7.4",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"lodash": "^4.17.21"
}
}
运行npm run build
:
可以看到,运行 npm run build
script 使用了 webpack.prod.js
。
开发环境打包出来的 bundle.js 大小比生产环境打包出来的 bundle.js 大,可以看出生产模式相对运行模式,会更多地压缩代码体积大小。
指定 mode
许多 library 通过与 process.env.NODE_ENV
环境变量关联,以决定 library 中应该引用哪些内容。
例如,当process.env.NODE_ENV
没有被设置为 'production'
时,某些 library 为了使调试变得容易,可能会添加额外的 log(日志记录) 和 test(测试) 功能。
并且,在使用 process.env.NODE_ENV === 'production'
时,一些 library 可能针对具体用户的环境,删除或添加一些重要代码,以进行代码执行方面的优化。
从 webpack v4 开始, 指定 mode
会自动地配置 DefinePlugin
。
技术上讲,
NODE_ENV
是一个由 Node.js 暴露给执行脚本的系统环境变量。通常用于决定在开发环境与生产环境(dev-vs-prod)下,server tools(服务期工具)、build scripts(构建脚本) 和 client-side libraries(客户端库) 的行为。
还要注意,任何位于 /src
的本地代码都可以关联到 process.env.NODE_ENV 环境变量,所以需要检查NODE_ENV
是有效的。例如:
src/index.js:
import { cube } from './math.js';
if (process.env.NODE_ENV !== 'production') {
console.log('Current 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());
压缩(Minification)
Webpack v4+ 默认在production mode
会压缩代码 。
注意,生产环境下默认使用 TerserPlugin
,是代码压缩方面比较好的选择。
如果决定尝试一些其他压缩插件,确保新插件也会按照 tree shake指南中所陈述的具有删除未引用代码(dead code)的能力,并将它作为
optimization.minimizer
。
源码映射(Source Mapping)
推荐在生产环境中启用 source map,因为它们对 debug(调试源码) 和运行 benchmark tests(基准测试) 很有帮助。
修改webpack.prod.js,在生产环境 中使用 source-map
选项,而不是我们在 开发环境 中用到的 inline-source-map
:
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map'
});
避免在生产中使用 inline-***
和 eval-***
,因为它们会增加 bundle 体积大小,并降低整体性能。
压缩 CSS
生产环境下的 CSS 进行压缩会非常重要,具体: 在生产环境下压缩 。
CLI 替代选项
上面许多选项都可以通过命令行参数来进行设置。
例如,optimize-minimize
可以使用 --optimization-minimize
进行设置;
mode
可以使用 --mode
进行设置;
运行 npx webpack --help=verbose
可以查看所有关于 CLI 的可用参数。
虽然这种简写方式很有用处,但还是建议通过 webpack 配置文件的方式进行使用,这样可以提高可配置能力。