How to upgrade webpack3 to webpack4?

This webpack upgrade has improved a lot of construction speed: production packaging has increased by 30%; Development and construction increased by 40%, and development and update increased by 70%

We have tried some build optimizations based on webpack3 before, such as introducing HappyPack to optimize the build speed, opening loader cache and optimizing package search path, etc. you can see the details Optimization of front-end webpack construction

However, with the passage of time, the effect of this optimization is becoming weaker and weaker, and the volume of the project in hand is becoming larger and larger, which has a great impact on the update speed of local opening heat and the release speed of production packaging.

Upgrading from webpack3 to webpack4 is imminent. This blog post will record some of the pitfalls I encountered during the upgrade process.

When you encounter these holes, find my article through the search engine. If you can solve the webpack configuration problem in your hand, then feel "Save my day" from your heart! “,”It helps me! “,”Solved my problem! “,”Works for me! ", I will feel that my blog post is very meaningful.

  • Upgrade to webpack 4
  • Remove Commons chunkplugin and use splitchunkplugin to split the code by default
  • Upgrade HTML webpack plugin
  • Remove extract text webpack plugin, introduce Mini CSS extract plugin and configure CSS loader
  • Configure mode property
  • Upgrade Vue loader to v14.0 two point two
  • Update chunkSortMode of HtmlWebpackPlugin
  • Fix size limit error
  • Rename app JS to generate vendors js
  • The configuration of mini CSS extract plugin is placed in webpack base. conf.js
  • Debug development environment available
  • Introducing analyzer to analyze package size
  • Packaging comparison between webpack3 and webpack4
  • Can the file be smaller? Can you build faster?
  • Upgrade Vue loader to v15 and replace happyPack with thread loader
  • Comparison of development dependency between webpack3 and webpack4
  • summary

Upgrade webpack to 4

"webpack": "^3.6.0" -> "webpack": "^4.43.0"

yarn add -D webpack@4.43.0

Remove Commons chunkplugin

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,
  // }),
];

Upgrade HTML webpack plugin

"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

Remove extract text webpack plugin, introduce Mini CSS extract plugin and configure 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",
        ],
      },
    ],
  },
};

Configure mode property

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";

Upgrade Vue loader

"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

Remove the postcss loader.

// postcss: generateLoaders()

Update chunkSortMode of HtmlWebpackPlugin

// https://www.cnblogs.com/wyliunan/p/10238717.html
Unhandled rejection Error: "dependency" is not a valid chunk sort mode

Set the chunkSortMode of HtmlWebpackPlugin to "auto": https://github.com/jantimon/html-webpack-plugin#options

Fix size limit error

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,
  },
};

Generate manifest JS to generate vendors js

// https://webpack.js.org/configuration/optimization/#optimizationsplitchunks
// Generate manifest js
optimization: {
    runtimeChunk: {
        name:'manifest'
    }
},
// https://webpack.js.org/plugins/split-chunks-plugin/#split-chunks-example-1
// Generate 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'),
  },

Debug development environment available

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>'

Install transform-es2015-modules-commonjs and Configuration in babelrc.

yarn add -D transform-es2015-modules-commonjs
// .babelrc
"plugins": [
    "transform-es2015-modules-commonjs"
]

Introducing analyzer to analyze package size

// 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());
}

Packaging comparison between webpack3 and webpack4

editionFile size (Parsed)File size (Gzipped)chunk numberProduction build timeDevelopment build timeTurn on heat and renew body feeling
webpack3.6.06.09MB1.76MB7352196ms70103msSlow (12079ms)
webpack4.43.07.07MB1.98MB8840727ms45448msFast (3394ms)

Machine parameters:
MacBook Pro (15-inch, 2019)
Processor 2.3 GHz Intel Core i9
Memory 16 GB 2400 MHz DDR4

Can the file be smaller? Can you build faster?

  • Use UglifyjsPlugin instead of TerserPlugin
  • OptimizeCSSPlugin is misplaced
  • If you manually configure splitChunks, you must also configure the parameters that are not configured
  • devtool changes from the slowest "source map" to false

To introduce TerserPlugin, you need to upgrade node to 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),
      }),
    ],
  }
}

Add the following configuration:

optimization: {
  splitChunks: {
    chunks: 'async',
    minSize: 30000,
    maxSize: 0,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',
    automaticNameMaxLength: 30,
  }
}

The current webpack3 and webpack4 packaging analysis:

editionFile size (Parsed)File size (Gzipped)chunk numberProduction build timeDevelopment build timeTurn on heat and renew body feeling
webpack3.6.06.09MB1.76MB7352196ms70103msSlow (12079ms)
webpack4. 43.0 (before optimization)7.07MB1.98MB8840727ms45448msFast (3394ms)
webpack4. 43.0 (after optimization)7.02MB1.98MB8834585ms45448msFast (3394ms)

Through comparison, it is found that the packaging speed is improved by about 5 seconds.

Upgrade Vue loader to v15 and introduce thread loader to accelerate 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

Why introduce thread loader to accelerate Vue loader?
Because HappyPack cannot accelerate vue-loader15.
https://github.com/vuejs/vue-loader/issues/1273

yyx990803:vue-loader 15 does not support HappyPack. Use thread-loader instead.

By the way, upgrade eslint loader to 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,
}),

The current webpack3 and webpack4 packaging analysis:

editionFile size (Parsed)File size (Gzipped)chunk numberProduction build timeDevelopment build timeTurn on heat and renew body feeling
webpack3.6.06.09MB1.76MB7352196ms70103msSlow (12079ms)
webpack4. 43.0 (before optimization)7.07MB1.98MB8840727ms45448msFast (3394ms)
webpack4. 43.0 (first optimization)7.02MB1.98MB8834585ms45448msFast (3394ms)
webpack4. 43.0 (second optimization)6.7MB1.91MB8834585ms41657msFast (3394ms)

Comparison of development dependency between webpack3 and 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"

summary

The upgrade from webpack3 to webpack4 mainly does the following things

  • Upgrade dependency: upgrade webpack major version to webpack4, Vue loader, HTML webpack plugin, etc
  • Code segmentation: Commons chunkplugin is removed; Introduce SplitChunksPlugin, set the mode attribute to production, and optimize to split the manifest and vendors in webpack3
  • Compress css: remove extract text webpack plugin; Introduce Mini css extract plugin and reconfigure sass loader, postcss loader and css loader with the loader of mini css extract plugin. It will build a css file separately for each js file containing css
  • Code hot update: upgrade webpack CLI and webpack dev server, and set the mode to development
  • Build acceleration: replace happypack with thread loader, multi line program local build and production build

reflect

  • Executive power is the primary productive force
  • This webpack upgrade has improved a lot of construction speed: production packaging has increased by 30%; Development and construction increased by 40%, and development and update increased by 70%
  • This webpack upgrade did not reduce the package size. There were attempts to use tree shaking, but they were unsuccessful. We need to continue to practice on tree shaking

I look forward to communicating with you and making progress together. Welcome to join the technical discussion group closely related to front-end development I created:

Strive to be an excellent front-end engineer!

Keywords: Front-end Webpack

Added by gfmitchell on Wed, 09 Feb 2022 03:13:02 +0200