这次webpack升级提升了不少构建速度:生产打包提升了30%;开发构建提升40%,开发热更新提升70% 之前尝试过一些在webpack3的基础上做的构建优化,例如引入HappyPack优化构建速度,开启loader缓存和优化包查找路径等等,详情可以查看前端webpack构建优化 但是随着时间的推移,这种优化产生的效果越来越弱化,手上的项目体积越来越大,对本地开发热更新速度和生产打包发布速度都有了很大的影响。 webpack3升级到webpack4迫在眉睫,这篇博文将记录一些我在升级过程中遇到的坑。 当你遇到这些坑时,通过搜索引擎找到我这篇文章,如果能够解决了手上的webpack配置问题,然后发自内心的感到 ”Save my day!“,”It helps me!“,”Solved my problem!“,”Works for me!“ ,我会感觉自己的这篇博文很有意义。 "webpack": "^3.6.0" -> "webpack": "^4.43.0" "html-webpack-plugin": "^2.30.1" -> "html-webpack-plugin": "^4.3.0" 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. "vue-loader": "^13.3.0" -> "vue-loader": "14.2.2" TypeError: Cannot read property 'vueOptions' of undefined vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config 移除 postcss-loader。 设置为 HtmlWebpackPlugin 的 chunkSortMode 为"auto": https://github.com/jantimon/html-webpack-plugin#options AssetsOverSizeLimitWarning: asset size limit: The following asset(s) exceed the recommended size limit (244 KiB 250000Byte). This can impact web performance. 安装transform-es2015-modules-commonjs并且在.babelrc中配置。 版本 文件大小(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+。 增加下面的配置: 现在的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秒的打包速度。 为什么引入thread-loader加速vue-loader? 因为HappyPack无法加速vue-loader15。 https://github.com/vuejs/vue-loader/issues/1273 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" error:despite it was not able to fulfill desired ordering with these modules: 现在的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到webpack4的升级,主要做了以下这些事情 期待和大家交流,共同进步,欢迎大家加入我创建的与前端开发密切相关的技术讨论小组: 微信公众号: 大大大前端 / excellent_developers Github博客: 趁你还年轻233的个人博客 SegmentFault专栏:趁你还年轻,做个优秀的前端工程师 努力成为优秀前端工程师!升级 webpack 到 4
yarn add -D [email protected]
移除 CommonsChunkPlugin
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
// 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
移除 extract-text-webpack-plugin,引入 mini-css-extract-plugin 并配置 css-loader
// 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",
],
},
],
},
};
配置 mode 属性
mode: "production";
升级 vue-loader
yarn add -D vue-loader@latest
// 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 [email protected]
(1:1) Unknown word
> 1 | // extracted by mini-css-extract-plugin
// postcss: generateLoaders()
更新 HtmlWebpackPlugin 的 chunkSortMode
// https://www.cnblogs.com/wyliunan/p/10238717.html
Unhandled rejection Error: "dependency" is not a valid chunk sort mode
修复大小限制的报错
// webpack.config.js
module.exports = {
performance: {
hints: "warning",
maxEntrypointSize: 5000 * 1024,
maxAssetSize: 5000 * 1024,
},
};
生成 manifest.js,生成 vendors.js
// 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>'
yarn add -D transform-es2015-modules-commonjs
// .babelrc
"plugins": [
"transform-es2015-modules-commonjs"
]
引入analyzer分析分析包大小
// 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());
}
webpack3与webpack4打包对比
文件可以更小一些吗?构建速度可以更快一些吗?
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,
}
}
升级vue-loader到v15并且引入thread-loader加速vue-loader
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
// 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',
],
},
]
new MiniCssExtractPlugin({
ignoreOrder: true,
}),
webpack3与webpack4开发依赖对比
// 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"
总结
反思