I had modified the company’s operation system before, and the accumulated codes over the years made it take an extremely long time to package and build each time, which was very uncomfortable. In anger, I upgraded the Webpack of the project from 2.x to 4.x, and the process that used to take 6 minutes in Jenkins only took 2 minutes now. I immediately felt relieved (~ ▽ ~)/and I also divided the project into multi-entry projects to implement incremental updates so that I didn’t have to pack so many files every time!

Ps: The following configuration is based on React. You can modify the configuration based on the framework and library used in actual projects


1. Points that can be optimized in the configuration

Let’s talk about what I found that could be improved during the upgrade, and what suggestions and ideas you might have.

1.1 Optimize third-party libraries

One of the simplest and most effective ways to optimize third-party libraries is to use WebPack’s DllPlugin. It can completely separate the third-party library that we often use but rarely modify from our own code, and it will judge whether to repackage the third-party library according to the index when packaging each time, greatly improving the packaging speed. Usage I won’t go into details, there are many online tutorials, interested can go to understand. The index to the library is typically stored in a manifest.json file. This file allows you to see how your project packages third-party libraries.

Optimization idea:

  • Assess the need for third party libraries installed in the project and do not use them if they are rarely usedwebpackthevendorEntry specified to pack in.
  • You can also upgrade some third-party libraries, such asreact v16contrastreact v15, plusreact-domIn terms of volume, it was reduced by 30%, so it was upgraded decisively.
  • An analysis of the manifest.json file reveals that some libraries are particularly large, such as the widely usedmoment.jsLibrary. And it turns outwebpackPut everything under the librarylocaleThe papers were packed in. Here are some files that support multiple languages. That is, we can passContextReplacementPluginPlugin to pick the files we need.
plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/),
]
Copy the code
  • Sometimes, through dependency analysis, there are two third-party libraries packaged into a project, one of which ises moduleEdition, and the other isumdVersion of the. Such asmomentBy importing ‘moment’es moduleVersion of the,localeFiles are imported using relative pathsumdVersion of the. At this point we can configure the alias library to point to the same version.
resolve: {
    alias: {
        'moment$': path.resolve('node_modules/moment/moment'),}}Copy the code
  • Sometimes a project doesn’t need the full functionality of a library, so consider using a lighter library instead, or using a custom castrated version (Echarts, available on the website), and useimport()Grammar andreact-loadableThis library wraps the React component as an asynchronous component and loads it as needed so that webpack extracts the asynchronous component as a chunk for the asynchronous load and doesn’t load it multiple times. Here’s how to extract.

1.2 Extract common code from chunk loaded asynchronously

Before WebPack4, we used CommonsChunkPlugin to extract asynchronous components, but now the CommonsChunkPlugin is deprecated and SplitChunksPlugin is used in two ways. One is configured in plugins, as in Webpack3, and the other is configured in splitChunks in the Optimization property in Webpack4

Optimization: {splitChunks: {// Split code rules (in chunks) maxInitialRequests: 4, // When initializing the load, the number of requests is greater than 4The '-',
        name: true// The name of the code block, set totrueAccording to the module and cache group key automatically generated, to achieve the solidification of chunkId, maintain the cache ability /* cache group, used to continue to subdivide the code. The cache group defaults to splitting modules in node_modules with a block of code called vendors, placing modules that are referenced twice at least into default. Alternatively, customized modules that meet the rules can be split into a chunk. */ cacheGroups: { default:false, // Disable default rules, vendors:false// Disable the default rule polyfill: {chunks:'initial'.test: 'polyfill',
            name: 'polyfill',
          },
          vendor: {
            chunks: 'initial'.test: 'vendor',
            name: 'vendor'}, // Extract the asynchronous component'async-vendor': {
            name: 'async-vendor',
            chunks: 'async'.test: (module) => {// Rules of the cache group, indicating that the qualified ones are added to the current cache groupif (/[\\/]node_modules[\\/](echarts|zrender)/.test(module.context)) {
                return false;
              }
              return/[\\/]node_modules[\\/]/.test(module.context); }},'async-biz': {
            name: 'async-biz',
            chunks: 'async', minChunks: 2, // split it if it is referenced more than 2 times}, // the CSS file is packed separately into a single file'styles': {
            name: 'styles'.test: /\.css$/,
            chunks: 'async',
            enforce: true,},},},},Copy the code

When extracting asynchronous loadable components, we need to use the following script in the business code for WebPack to recognize

import Loadable from 'react-loadable';
const loder1 = import(/* webpackChunkName: "chunkname2"* /'path/to/module2') const Component = Loadable({loadingComponent, loadingComponent, // loding)Copy the code

1.3 Rational use of asynchronous loading

If the first screen in our project also uses the asynchronous loading method and the components in async-Vendor are used, the first screen will load async-vendor and cache at the same time, so that there is no need to load new code again after the components in async-Vendor are used in the subsequent pages. But that might slow down our first screen. The first solution is to split the first screen of Async-vendor. Or cancel asynchronous loading of the first screen page and package it in main, so as to avoid loading async-vendor and greatly reduce the volume of the first screen.

1.4 Isolate the WebPack Runtime code

When Webpack runs on the client, it will first load webpack-related codes, such as require function, etc. This part of code will change with every modification of business code, because it will contain information such as chunk ID that is easy to change. If it is not extracted, it will be packaged in the vendor, causing the vendor to be reloaded by the user every time. The extracted configuration is written in the runtimeChunk configuration in the Optimization property:

optimization: {
    runtimeChunk: {
        name: 'manifest',}}Copy the code

1.5 Webpack internal optimization

Prior to Webpackage 4, internal optimization used two plug-ins: HashedModuleIdsPlugin and ModuleConcatenationPlugin by default, webpack will use a digital ID for each module, this can result in the same module after the add or remove other modules, ID change, is not conducive to the cache. To solve this problem, there are two options: NamedModulesPlugin, which uses the module’s file path as the module name, and HashedModuleIdsPlugin, which performs MD5 processing on the path. Because the former is faster and the latter packs smaller files, you should choose the former for development and the latter for production. ModuleConcatenationPlugin main scope is to ascend, will all modules in the same scope, on the one hand can improve the running speed, on the other hand also can reduce the file size. If your code is written in the ES module. In Webpackage 4, simply set moduleIds to hashed or named and mode to production in the Optimization configuration item.

Mode:'production',
optimization : {
    moduleIds: 'hashed',}Copy the code

1.6 the Babel – polyfill optimization

At present, the method I use in my project is to name a polyfill file from babel-Polyfill, but annotate out most of the import, only keep the basic requirements of the project, and introduce them in the project entry file.

{polyfill: path.join(process.cwd(),'path/to/your/polyfill'),},Copy the code

Check out some excellent articles about polyfill optimization from others:

  • ES6 and Babel you didn’t know
  • Polyfill.io
  • Proficient in front-end Polyfill solutions

2. Refer to the article

Webpack4 – SplitChunksPlugin Usage Guide Multi-page application webPack4 configuration optimization and step on the pit record Webpack configuration notes (this is my colleague’s blog ha ha, it has the specific configuration of the webpack we are using now, If you are interested, you can go to the inside to have a closer look and learn. He is a master. You can pay more attention to him.

3. The conclusion

The above optimization is based on a certain understanding of Webpack, if you are not very familiar with Webpack, I recommend to learn the basics of Webpack Chinese documentation, and go to the nuggets above search for more excellent articles about Webpack!