webpack4 也發佈3個月了,一直想體驗一下。最近項目不忙,也感受項目編譯和打包的速度略慢,索性就把一個由 vue-cli 生成的項目從 webpack3 升級到 webpack4,期間遇到的問題也記錄一下。javascript
npm i webpack@latest webpack-cli --save-dev
css
出現報錯信息:html
根據報錯信息,逐個升級它們:vue
npm install extract-text-webpack-plugin@latest html-webpack-plugin@latest inject-loader@latest webpack-dev-middleware@latest webpack-dev-server@latest
java
順便把其它 loaders
及 plugins
都升級到最新版本node
npm install webpack-bundle-analyzer@latest vue-template-compiler@latest webpack-merge@latest friendly-errors-webpack-plugin@latest copy-webpack-plugin@latest optimize-css-assets-webpack-plugin@latest
webpack
npm install css-loader@latest file-loader@latest url-loader@latest less-loader@latest postcss-loader@latest vue-loader@latest vue-style-loader@latest
ios
升級的版本信息以下:git
webpack@4.8.3github
webpack-cli@2.1.4
html-webpack-plugin@3.2.0
extract-text-webpack-plugin@4.0.0-beta.0
webpack-dev-server@3.1.4
webpack-dev-middleware@3.1.3
friendly-errors-webpack-plugin@1.7.0
webpack-bundle-analyzer@2.13.1
webpack-merge@4.1.2
optimize-css-assets-webpack-plugin@4.0.1
copy-webpack-plugin@4.5.1
vue-template-compiler@2.5.16
postcss-loader@2.1.5
inject-loader@4.0.1
less-loader@4.1.0
css-loader@0.28.11
vue-style-loader@4.1.0
file-loader@1.1.11
vue-loader@15.2.0
url-loader@1.0.1
運行 npm run dev
,又出現 eslint
的報錯信息
npm i eslint@latest eslint-config-standard@latest eslint-friendly-formatter@latest eslint-loader@latest eslint-plugin-import@latest eslint-plugin-node@latest eslint-plugin-promise@latest eslint-plugin-standard@latest eslint-plugin-vue@latest
相比於 webpack 3,webpack 4 的配置部分改變,具體以下:
在 dev 環境中,添加 mode: 'development'
,去掉 webpack.NamedModulesPlugin 及 webpack.NoEmitOnErrorsPlugin 插件,由於 webpack4 開發模式已經內置。
// webpack.dev.conf.js
module.exports = {
// ...
mode: 'development',
// ...
plugins: {
// new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
// new webpack.NoEmitOnErrorsPlugin(),
}
}
複製代碼
在 prod 環境中添加 mode 配置,用 optimization 代替之前的 webpack.optimize.CommonsChunkPlugin 、 uglifyjs-webpack-plugin 、 webpack.optimize.ModuleConcatenationPlugin 相關配置及引用
// webpack.production.prod.js
// const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const webpackConfig = merge(baseWebpackConfig, {
// ...
mode: 'production',
// webpack4 內置
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
chunks: 'initial',
name: 'vendors',
},
'async-vendors': {
test: /[\\/]node_modules[\\/]/,
minChunks: 2,
chunks: 'async',
name: 'async-vendors'
}
}
},
runtimeChunk: { name: 'runtime' }
},
// ...
pluins: {
// new UglifyJsPlugin({
// uglifyOptions: {
// beautify: false,
// comments: false,
// compress: {
// warnings: false,
// drop_console: true
// }
// },
// sourceMap: config.build.productionSourceMap,
// parallel: true
// }),
// ...
// enable scope hoisting
// new webpack.optimize.ModuleConcatenationPlugin(),
// split vendor js into its own file
// 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
// )
// }
// }),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
// new webpack.optimize.CommonsChunkPlugin({
// name: 'manifest',
// minChunks: Infinity
// }),
// // This instance extracts shared chunks from code splitted chunks and bundles them
// // in a separate chunk, similar to the vendor chunk
// // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
// new webpack.optimize.CommonsChunkPlugin({
// name: 'app',
// async: 'vendor-async',
// children: true,
// minChunks: 3
// }),
}
}
複製代碼
運行 npm run dev
,又出現 vue-loader
的報錯信息:
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
爲了解決上面的 vue-loader
的報錯,在 webpack.base.conf.js 中添加配置
// webpack.base.conf.js
const { VueLoaderPlugin } = require('vue-loader')
//...
plugins: [
new VueLoaderPlugin()
]
複製代碼
運行 npm run dev
,報錯:
雖然有報錯信息,可是沒有顯示錯誤的具體位置。在網上查找了好久,發現有人說他在template file
和 routing file
出現了循環引用。 根據這個,我忽然發如今 main.js
和 向後臺請求的api文件中都引用了路由文件,api.js
中引用是爲了寫 axios
攔截器,出現 40一、404 或 500 時,跳轉相應頁面。 註釋掉 api.js
中對 router
的引用,確實能夠成功運行了,可是 40一、40四、500 跳頁的問題就無法解決了。 可是後來我又找到了另外一種方法,在 HtmlWebpackPlugin
插件中添加或者修改 chunksSortMode: none
。(不過不肯定這方式會不會對性能優化等等有影響)
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true,
chunksSortMode: 'none'
}),
複製代碼
運行 npm run dev
,沒問題了。
接下來試試生產環境,運行 npm run build
。1分鐘過去了……5分鐘過去了……中午吃飯1個小時都過去了……竟然沒反應,也沒有報錯。又嘗試了好幾回,依舊如此。在網上也沒有找到相關問題。
因而我只好在 build.js
中逐步打斷點,最後發現是 extract-text-webpack-plugin
插件的問題。 查找資料瞭解到 extract-text-webpack-plugin
實際上是適配 webpack3 的,有個 extract-text-webpack-plugin@4.0.0-beta.0
版本能夠適配 webpack4,可是我用的就是這個版本。
有人推薦用 mini-css-extract-plugin
來替代它,我就根據 文檔嘗試配置一下。
須要在 webpack.prod.conf.js
和 utils.js
兩個文件中配置。
// webpack.prod.conf.js
// const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// ...
// extract css into its own file
// new ExtractTextPlugin({
// ...
// })
// 升級 webpack4, 由 ExtractTextPlugin 改用 MiniCssExtractPlugin
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
allChunks: true,
}),
複製代碼
// utils.js
// const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// ...
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
// if (options.extract) {
// return ExtractTextPlugin.extract({
// use: loaders,
// fallback: 'vue-style-loader'
// })
// } else {
// return ['vue-style-loader'].concat(loaders)
// }
// 升級 webpack4, 由 ExtractTextPlugin 改用 MiniCssExtractPlugin
return [
options.extract ? MiniCssExtractPlugin.loader : 'vue-style-loader',
].concat(loaders)
}
複製代碼
運行 npm run build
,終於成功了。
附上 webpack3 和 webpack4 的打包對比圖,能夠看到,體積少了一點(後期我會在邊學習 webpack 邊進行優化)可是打包的時間減小了一半,也不枉費我這麼辛苦的升級。