此次webpack升級提高了很多構建速度:生產打包提高了30%;開發構建提高40%,開發熱更新提高70%
以前嘗試過一些在webpack3的基礎上作的構建優化,例如引入HappyPack優化構建速度,開啓loader緩存和優化包查找路徑等等,詳情能夠查看前端webpack構建優化css
可是隨着時間的推移,這種優化產生的效果愈來愈弱化,手上的項目體積愈來愈大,對本地開發熱更新速度和生產打包發佈速度都有了很大的影響。html
webpack3升級到webpack4迫在眉睫,這篇博文將記錄一些我在升級過程當中遇到的坑。前端
當你遇到這些坑時,經過搜索引擎找到我這篇文章,若是可以解決了手上的webpack配置問題,而後發自心裏的感到 」Save my day!「,」It helps me!「,」Solved my problem!「,」Works for me!「 ,我會感受本身的這篇博文頗有意義。vue
"webpack": "^3.6.0" -> "webpack": "^4.43.0"node
yarn add -D webpack@4.43.0
plugins: [ // // split vendor js into its own file // new webpack.optimize.CommonsChunkPlugin({ // name: 'vendor', // }), // // 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, // }), ];
"html-webpack-plugin": "^2.30.1" -> "html-webpack-plugin": "^4.3.0"webpack
// https://stackoverflow.com/questions/49942558/deprecationwarning-tapable-plugin-is-deprecated-use-new-api-on-hooks-instea // error Tapable.apply is deprecated. Call apply on the plugin directly instead
yarn add -D html-webpack-plugin@latest
// const ExtractTextPlugin = require('extract-text-webpack-plugin'); // plugins:[ // extract css into its own file // 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, // }), // ] // extract: true // if (options.extract) { // return ExtractTextPlugin.extract({ // use: loaders, // fallback: 'vue-style-loader', // }); // }
yarn add -D mini-css-extract-plugin
// webpack.prod.conf.js const MiniCssExtractPlugin = require("mini-css-extract-plugin"); plugins: [ new MiniCssExtractPlugin(filename: utils.assetsPath('css/[name].[contenthash].css')) ];
// webpack.base.conf.js module.exports = { module: { rules: [ { test: /\.(sa|sc|c)ss$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { hmr: process.env.NODE_ENV === "development", }, }, "css-loader", "postcss-loader", "sass-loader", ], }, ], }, };
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
mode: "production";
"vue-loader": "^13.3.0" -> "vue-loader": "14.2.2"git
TypeError: Cannot read property ' vueOptions' of undefined
yarn add -D vue-loader@latest
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config
// https://github.com/symfony/webpack-encore/issues/311 You probably use vue-loader v15 which was released yesterday and introduces a lot of changes compared to v14. One of these changes is that you have to use an extra plugin: VueLoaderPlugin (that's not handled yet by Encore). In the meantime could you try removing your version of the vue-loader/VueLoaderPlugin and adding vue-loader@^14.2.2 instead?
yarn add -D vue-loader@14.2.2
(1:1) Unknown word > 1 | // extracted by mini-css-extract-plugin
移除 postcss-loader。github
// postcss: generateLoaders()
// https://www.cnblogs.com/wyliunan/p/10238717.html Unhandled rejection Error: "dependency" is not a valid chunk sort mode
設置爲 HtmlWebpackPlugin 的 chunkSortMode 爲"auto": https://github.com/jantimon/h...web
AssetsOverSizeLimitWarning: asset size limit: The following asset(s) exceed the recommended size limit (244 KiB 250000Byte).
This can impact web performance.
// webpack.config.js module.exports = { performance: { hints: "warning", maxEntrypointSize: 5000 * 1024, maxAssetSize: 5000 * 1024, }, };
// https://webpack.js.org/configuration/optimization/#optimizationsplitchunks // 生成manifest.js optimization: { runtimeChunk: { name:'manifest' } },
// https://webpack.js.org/plugins/split-chunks-plugin/#split-chunks-example-1 // 生成 vendors.js optimization: { splitChunks: { cacheGroups: { commons: { test: /[\\/]node_modules[\\/]/, name: 'vendors', chunks: 'all', }, }, }, }
output: { - chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'), + chunkFilename: utils.assetsPath('js/[name].[chunkhash].js'), },
Error: Cannot find module 'webpack/bin/config-yargs' https://github.com/mzgoddard/jest-webpack/issues/27
"webpack-cli": "^2.1.3", "webpack-dev-server": "^3.1.4"
mode: 'development',
// webpack Error: Callback was already called. // https://github.com/webpack-contrib/mini-css-extract-plugin/issues/493 // webpack.dev.js plugins:[ new MiniCssExtractPlugin(), ]
// https://segmentfault.com/q/1010000012054980 // BaseClient.js:12 Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
安裝transform-es2015-modules-commonjs而且在.babelrc中配置。npm
yarn add -D transform-es2015-modules-commonjs
// .babelrc "plugins": [ "transform-es2015-modules-commonjs" ]
// package.json scripts:{ "build:analyse": "NODE_ENV=production source_map=false npm_config_report=true node build/build.js" }
// webpack.prod.conf.js if (config.build.bundleAnalyzerReport) { const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; webpackConfig.plugins.push(new BundleAnalyzerPlugin()); }
版本 | 文件大小(Parsed) | 文件大小(Gzipped) | chunk數 | 生產構建時間 | 開發構建時間 | 開發熱更新體感 |
---|---|---|---|---|---|---|
webpack3.6.0 | 6.09MB | 1.76MB | 73 | 52196ms | 70103ms | 慢(12079ms) |
webpack4.43.0 | 7.07MB | 1.98MB | 88 | 40727ms | 45448ms | 快(3394ms) |
機器參數:
MacBook Pro (15-inch, 2019)
處理器 2.3 GHz Intel Core i9
內存 16 GB 2400 MHz DDR4
引入TerserPlugin的話,須要首先升級node到v10.17.0+。
sudo n v10.17.0
const TerserPlugin = require('terser-webpack-plugin'); module.exports = { optimization: { minimize: true, minimizer: [ // Compress extracted CSS. We are using this plugin so that possible // duplicated CSS from different presentation can be deduped. new OptimizeCSSPlugin({ cssProcessorOptions: config.build.productionSourceMap ? { safe: true, map: { inline: false } } : { safe: true }, }), new TerserPlugin({ cache: true, parallel: true, sourceMap: Boolean(config.build.productionSourceMap), }), ], } }
增長下面的配置:
optimization: { splitChunks: { chunks: 'async', minSize: 30000, maxSize: 0, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: '~', automaticNameMaxLength: 30, } }
如今的webpack3和webpack4打包分析:
版本 | 文件大小(Parsed) | 文件大小(Gzipped) | chunk數 | 生產構建時間 | 開發構建時間 | 開發熱更新體感 |
---|---|---|---|---|---|---|
webpack3.6.0 | 6.09MB | 1.76MB | 73 | 52196ms | 70103ms | 慢(12079ms) |
webpack4.43.0(優化前) | 7.07MB | 1.98MB | 88 | 40727ms | 45448ms | 快(3394ms) |
webpack4.43.0(優化後) | 7.02MB | 1.98MB | 88 | 34585ms | 45448ms | 快(3394ms) |
經過對比發現,提高了大概5秒的打包速度。
warning No parser and no filepath given, using 'babel' the parser now but this will throw an error in the future. Please specify a parser or a filepath so one can be inferred
爲何引入thread-loader加速vue-loader?
由於HappyPack沒法加速vue-loader15。
https://github.com/vuejs/vue-...
yyx990803:vue-loader 15 does not support HappyPack. Use thread-loader instead.
順便升級eslint-loader到4。
"eslint-loader": "^1.7.1"->"eslint-loader": "^4.0.2"
// plugins: [ // new HappyPack({ // id: 'happy-eslint-loader', // threadPool: happyThreadPool, // loaders: ['eslint-loader?cacheDirectory=true'], // }), // new HappyPack({ // id: 'happy-vue-loader', // threadPool: happyThreadPool, // loaders: ['vue-loader?cacheDirectory=true'], // }), // new HappyPack({ // id: 'happy-babel-loader', // threadPool: happyThreadPool, // loaders: ['babel-loader?cacheDirectory=true'], // }), // ]
rules: [ { test: /\.(js|vue)$/, use: [ { loader: 'thread-loader' }, { loader: 'eslint-loader', options: { formatter: require('eslint-friendly-formatter'), emitWarning: !config.dev.showEslintErrorsInOverlay, }, }, ], enforce: 'pre', include: [resolve('src'), resolve('test')], }, { test: /\.vue$/, use: ['thread-loader', 'vue-loader'], exclude: (file) => /node_modules/.test(file) && !/\.vue\.js/.test(file), }, { test: /\.js$/, use: ['thread-loader', 'babel-loader'], include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')], }, { test: /\.(sa|sc|c)ss$/, use: [ { loader: process.env.NODE_ENV === 'development' ? 'vue-style-loader' : MiniCssExtractPlugin.loader, options: { hmr: process.env.NODE_ENV === 'development', }, }, 'css-loader', 'postcss-loader', 'sass-loader', ], }, ]
error:despite it was not able to fulfill desired ordering with these modules:
new MiniCssExtractPlugin({ ignoreOrder: true, }),
如今的webpack3和webpack4打包分析:
版本 | 文件大小(Parsed) | 文件大小(Gzipped) | chunk數 | 生產構建時間 | 開發構建時間 | 開發熱更新體感 |
---|---|---|---|---|---|---|
webpack3.6.0 | 6.09MB | 1.76MB | 73 | 52196ms | 70103ms | 慢(12079ms) |
webpack4.43.0(優化前) | 7.07MB | 1.98MB | 88 | 40727ms | 45448ms | 快(3394ms) |
webpack4.43.0(第一次優化) | 7.02MB | 1.98MB | 88 | 34585ms | 45448ms | 快(3394ms) |
webpack4.43.0(第二次優化) | 6.7MB | 1.91MB | 88 | 34585ms | 41657ms | 快(3394ms) |
// webpack3 "webpack": "^3.6.0" "webpack-dev-server": "^2.9.1" "eslint-loader": "^1.7.1" "vue-loader": "^13.3.0" "happypack": "^5.0.0" "html-webpack-plugin": "^2.30.1" "extract-text-webpack-plugin": "^3.0.0" "uglifyjs-webpack-plugin": "^1.1.1"
// webpack4 "webpack": "^4.43.0" "webpack-cli": "^3.3.11" "webpack-dev-server": "^3.7.2" "thread-loader": "^2.1.3" "eslint-loader": "^4.0.2" "vue-loader": "^15.9.2" "html-webpack-plugin": "^4.3.0" "mini-css-extract-plugin": "^0.9.0" "terser-webpack-plugin": "^3.0.1" "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2"
webpack3到webpack4的升級,主要作了如下這些事情
期待和你們交流,共同進步,歡迎你們加入我建立的與前端開發密切相關的技術討論小組:
- 微信公衆號: 生活在瀏覽器裏的咱們 / excellent_developers
- Github博客: 趁你還年輕233的我的博客
- SegmentFault專欄:趁你還年輕,作個優秀的前端工程師
- Leetcode討論微信羣:Z2Fva2FpMjAxMDA4MDE=(加我微信拉你進羣)
努力成爲優秀前端工程師!