Skip to main content

如何将webpack3升级至webpack4

背景#

原项目由vue-cli2快速构建, 几年过去了webpack5已经发布,迫于项目逐渐扩大且业务需求, webpack版本升级迫在眉睫。 以下记录了升级过程及问题解决方案

难点#

相关最新安装包不匹配造成无法按照预期运行

针对development#

升级webpack及周边#

⚠️webpack-dev-server需要与webpack匹配, 否则报错

"webpack": "^4.44.2", // 3.6.0 -> 4.44.2
"webpack-cli": "^3.3.12", // add
"webpack-dev-server": "^3.11.0", // 2.9.1 -> 3.11.0
npm i -D webpack-bundle-analyzer@latest // 2.9.0 -> 4.3.0

添加mode (v4新)#

mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',

参照官网指南, 移除废弃API#

https://v4.webpack.docschina.org/migrate/4/

  • 移除NamedModulesPlugin,NoEmitOnErrorsPlugin插件
// new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
// new webpack.NoEmitOnErrorsPlugin(),
  • 移除DefinePlugin
  • UglifyJsPlugin

升级html编译插件html-webpack-plugin#

错误提示:compilation.mainTemplate.applyPluginsWaterfall('asset-path', outputOptions.filename

npm i html-webpack-plugin@latest --dev // 2.30.1 -> 4.5.0

升级vue-loader,使用VueLoaderPlugin替换vueLoaderConfig#

错误提示: Cannot read property 'vue' of undefined

npm i -D vue-loader@latest // 13.3.0 -> 15.9.6

移除vueLoaderConfig, 增加VueLoaderPlugin ⚠️ options 字段改为 loader

//const vueLoaderConfig = require('./vue-loader.conf')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
...,
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
// options: vueLoaderConfig
},
]
},
plugins: [
new VueLoaderPlugin()
]
}

移除webpack-dev-server/client#

错误提示:Cannot assign to read only property 'exports' of object '[object Object]' 移除resolve('node_modules/webpack-dev-server/client') ​

针对production#

废弃CommonsChunkPlugin由optimization 代替#

webpack.optimize.CommonsChunkPlugin has been removed

  • vendor
  • manifest
  • vendor-async
plugins: [
// new webpack.optimize.CommonsChunkPlugin({
// name: 'vendor',
// minChunks (module) {
// // any required modules inside node_modules are extracted to vendor
// return (
// module.resource &&
// /\.js$/.test(module.resource) &&
// module.resource.indexOf(
// path.join(__dirname, '../node_modules')
// ) === 0
// )
// }
// }),
// new webpack.optimize.CommonsChunkPlugin({
// name: 'manifest',
// minChunks: Infinity
// }),
// new webpack.optimize.CommonsChunkPlugin({
// name: 'app',
// async: 'vendor-async',
// children: true,
// minChunks: 3
// }),
]
optimization: {
// minimize: true,
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
chunks: 'initial',
name: 'vendors',
},
'async-vendors': {
test: /[\\/]node_modules[\\/]/,
minChunks: 3,
chunks: 'async',
name: 'async-vendors',
},
manifest: {
test: /[\\/]src[\\/]/,
minSize: 0,
minChunks: 2,
priority: 9
}
}
}
}

废弃extract-text-webpack-plugin由mini-css-extract-plugin代替#

Chunk.entrypoints: Use Chunks.groupsIterable and filter

extract-text-webpack-plugin // remove
npm i mini-css-extract-plugin@latest --dev

webpack.prod.js

// const ExtractTextPlugin = require('extract-text-webpack-plugin')
// new ExtractTextPlugin({
// filename: utils.assetsPath('css/[name].[contenthash].css'),
// // Setting the following option to `false` will not extract CSS from codesplit chunks.
// // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
// allChunks: true
// }),
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
allChunks: true,
ignoreOrder: true
}),

告警: WARNING in chunk 1 [mini-css-extract-plugin] Conflicting order. 

ignoreOrder: true

utils.js

if (options.extract) {
// return ExtractTextPlugin.extract({
// use: loaders,
// fallback: 'vue-style-loader'
// })
return [MiniCssExtractPlugin.loader].concat(loaders)
}

修改chunksSortMode#

错误提示: Unhandled rejection Error: "dependency" is not a valid chunk sort mode

// HtmlWebpackPlugin 中配置
chunksSortMode: 'auto'

告警: Unhandled rejection Error: "dependency" is not a valid chunk sort mode#

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB). This can impact web performance. ​

升级成果: 打包时间提升 26.5%, 体积减小65.5%#

13831ms -> 10160ms 14.78s 16M -> 6M ​

影响不大的升级#

升级webpack-merge#

npm i webpack-merge@latest --dev // 4.1.0 -> 5.7.3
// error merge is not a function
const {merge} = reuqire('webpack-merge')

升级webpack-bundle-analyzer#

npm i -D webpack-bundle-analyzer@latest // ^2.9.0 -> ^4.3.0
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
"build:report": "npm_config_report=true node build_vue_script/build.js"

升级plugin#

vue-template-compiler@latest
friendly-errors-webpack-plugin@latest
copy-webpack-plugin@latest
optimize-css-assets-webpack-plugin@latest

升级css#

npm install --save-dev css-loader@latest
npm install --save-dev postcss-loader@latest
postcss-import@latest
postcss-import@latest
sass-loader@latest
npm install css-loader@latest
file-loader@latest
url-loader@latest
less-loader@latest
postcss-loader@latest
vue-loader@latest
vue-style-loader@latest -D

错误提示:Error: true is not a PostCSS plugin

升级eslint#

npm i -D eslint@latest
eslint-loader@latest 已被废弃 替换eslint-webpack-plugin
eslint-config-standard@latest
eslint-friendly-formatter@latest
eslint-plugin-import@latest
eslint-plugin-node@latest
eslint-plugin-promise@latest
eslint-plugin-standard@latest
eslint-plugin-vue@latest
eslint-plugin-html@latest
module.exports = {
// ...
module: {
rules: [
// {
// test: /\.js$/,
// exclude: /node_modules/,
// loader: 'eslint-loader',
// options: {
// // eslint options (if necessary)
// },
// },
],
},
// ...
};
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
// ...
plugins: [new ESLintPlugin(options)],
// ...
};

参考:

webpack4-documnet