本文详细记录了从 Webpack 3 升级至 Webpack 4 的完整过程。重点分析了 webpack-cli 的安装、mode 模式对 DefinePlugin 和 UglifyJsPlugin 的影响,以及 CommonsChunkPlugin 移除后的替代方案。针对 extract-text-webpack-plugin 报错、HappyPack 版本兼容及 process.env.NODE_ENV 作用域差异等常见坑点提供了具体解决方案,并给出了平滑升级建议。
Webpack 4 升级背景与日志概览
此前各大技术平台广泛报道了 Webpack 新版发布的消息,我曾尝试升级但因部分插件兼容性问题未能成功。如今时机已成熟,本文旨在记录在项目中升级 Webpack 4 时遇到的具体问题及解决方案。
查阅更新日志
在执行安装更新前,建议先通读官方更新日志。对于大多数用户而言,迁移过程中需重点关注以下核心变更点:
- 在命令行界面执行打包指令时,必须安装
webpack-cli以支持 CLI 功能; - 打包时必须明确指定打包模式为
production或development。不同模式会加载不同的默认配置,此时webpack.DefinePlugin插件中process.env.NODE_ENV的值无需手动定义,Webpack 将根据当前模式自动注入; - 不再需要在
plugin中显式配置new webpack.optimize.UglifyJsPlugin,只需在顶层配置中开启相应开关即可。同时,production模式默认开启代码压缩功能,开发者可通过optimization.minimizer配置项指定自定义的压缩工具库; CommonsChunkPlugin已被移除,其功能已迁移至optimization.splitChunks ,以及optimization.runtimeChunk配置项中。
基础配置迁移步骤
迁移
- 首先安装最新版本的
webpack、webpack-cli以及webpack-dev-server; - 分别为开发和生产环境配置
mode,移除原有的webpack.DefinePlugin相关配置,并清理package.json中启动脚本里关于NODE_ENV环境变量定义的区别处理逻辑; - 移除对
new webpack.optimize.UglifyJsPlugin和ModuleConcatenationPlugin的配置引用。
常见插件报错与解决方案
爬坑

完成上述基础配置后,遇到的第一个问题便是打包过程中 extract-text-webpack-plugin 插件报错崩溃。针对此问题,提供两种解决方案:
- 方案一:安装指定版本的
extract-text-webpack-plugin,即使用其@next版本; - 方案二:使用
mini-css-extract-plugin插件进行替代。
若采用方案二,需注意在生产环境打包时需明确指定 css 压缩库配置,并同时写入 js 压缩库配置。因为一旦指定了 optimization.minimizer,Webpack 将弃用内置的代码压缩功能:
/* webpack.config.js */
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = () => {
const config = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader?importLoaders=1',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader?importLoaders=1',
'postcss-loader',
'less-loader'
]
}
]
},
resolve: {
extensions: ['.js', '.jsx', '.less']
}
};
if (process.env.NODE_ENV === 'development') {
config.module.rules[0].use = [
'css-hot-loader',
MiniCssExtractPlugin.loader,
'css-loader?importLoaders=1',
'postcss-loader'
];
config.module.rules[1].use = [
'css-hot-loader',
MiniCssExtractPlugin.loader,
'css-loader?importLoaders=1',
'postcss-loader',
{
loader: 'less-loader',
options: {
modifyVars: theme
}
}
];
}
return config;
};
/* webpack.config.prod.js */
const merge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const webpackBaseConfig = require('./webpack.config')();
module.exports = merge(webpackBaseConfig, {
mode: 'production',
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
uglifyOptions: {
compress: {
warnings: false,
drop_debugger: true,
drop_console: false
}
}
}),
new OptimizeCSSAssetsPlugin({})
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].css'
})
]
});
happypack 报错,问题不大,升级至 @5.0.0-beta.3 版本即可解决(建议 happypack 与 extract-text-webpack-plugin 搭配使用效果更佳,mini-css-extract-plugin 尚未测试)。webpack-browser-plugin 报错,问题不大,直接弃用该插件,并在 devServer 配置中设置 open 和 openPage 即可。
process.env.NODE_ENV 作用域差异处理
在上述配置中,我使用了判断语句 process.env.NODE_ENV === 'development' 在开发配置中引入了 css-hot-loader,但实际运行时获取到的变量值却是 undefined。这是什么原因?查阅更新日志可知:
process.env.NODE_ENV are set to production or development (only in built code, not in config)
这句话的意思是,在最终构建生成的业务代码中可以获取到该变量,但在 Webpack 的打包配置文件中无法直接获取。经实际验证,确实如此。因此,我在 package.json 的开发启动脚本中手动添加了 NODE_ENV='development' 环境变量定义。
升级总结与建议
最后
总体而言,目前的升级时机已经成熟,大多数常用功能和插件都提供了平滑的升级路径或替代方案。建议在开始升级前,先安装最新发布的对应插件版本。你也可以参考我的项目配置模板 react-with-mobx-template。
此外,部分插件的 API 也发生了变更。如果你是插件开发者,可以尝试发布适配新版本。例如,在使用我自己编写的版本号提取插件 webpack-version-plugin 时,发现 compiler.plugin 已被标记为过时。在 webpack@v4 中,应使用最新的 compiler.hooks.emit.tap 来触发相关事件。