这次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"
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"
// 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"
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。
// 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...
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中配置。
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专栏:趁你还年轻,做个优秀的前端工程师
webpack 在前端工程中随处可见,当前流行的 vue, react, weex 等解决方案都推崇 webpack 作为打包工具。前端工具云集的时代,这是你值得选择的之一。
webpack是前端工程构建的一套工具,为什么一个程序称之为一套呢,是因为webpack其实是npm的一个模块,使用起来的话,这期间还需要很多其它模块来进行支持,所以我称之为一套工具。
本文从一个小Demo开始,通过不断增加功能来说明webpack的基本配置,只针对新手。webpack基本的配置就可以熟悉了,会引入loader,配置loader选项,会设置alias,会用plugins差不多。
Plugins是webpack的基础,我们都知道webpage的plugin是基于事件机制工作的,这样最大的好处是易于扩展。讲解如果扩展内置插件和其他插件,以及我们常用的Plugins插件
webpack技巧的总结:进度汇报、压缩、复数文件打包、分离app文件与第三方库文件、资源映射、输出css文件、开发模式、分析包的大小、更小的react项目、更小的Lodash、引入文件夹中所有文件、清除extract-text-webpack-plugin日志。
Webpack 作为目前最流行的前端构建工具之一,在 vue/react 等 Framework 的生态圈中都占据重要地位。在开发现代 Web 应用的过程中,Webpack 和我们的开发过程和发布过程都息息相关,如何改善 Webpack 构建打包的性能也关系到我们开发和发布部署的效率。
新版 Webpack 中我们所做的每一个更新目的都在于此,为了当大家在使用 Webpack 的时候敏捷连续毫无顿挫感。 webpack 4 进行构建性能测试,得出的结果非常有趣。结果很惊人,构建时间降低了 60%-98%!
Webpack 是一个现代 JavaScript 应用程序的模块打包器 (module bundler) 。当 Webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块
Tobias Koppers是一位自由软件开发者,家住德国纽伦堡。他因写出webpack这个已有数百万开发者使用的开源软件而名噪一时。他目前专注于JavaScript和开源项目。以下是我对他个人的专访,希望对大家有所启发。
本文讲述css-loader开启css模块功能之后,如何与引用的npm包中样式文件不产生冲突。比如antd-mobilenpm包的引入。在不做特殊处理的前提下,样式文件将会被转译成css module。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!