Detailed usage of SplitChunks plugin in Webpack

Preface

What is the SplitChunks plugin?
Simply put, it is a plug-in that extracts or separates code in Webpack. The main function is to extract common code, prevent code from being repeatedly packaged, split oversized js files, and merge scattered js files.
When it comes to front-end optimization, extracting common code is an indispensable method.
Before the advent of Webpack, the extraction of common code was artificially processed, and the function of the SplitChunks plug-in was to let Webpack extract the common code for you through configuration. The original intention of the founder of Webpack was also to have more time to write more code, so this purely physical labor was handed over to Webpack.

1. If you want to benefit from your work, you must first sharpen your tools

Because the SplitChunks plugin will extract the modules and package them to generate js files.
First learn to name the js file generated by the package, otherwise it is difficult to confirm whether the js file generated by the package is what you want.
There are several ways to name the generated js file in Webpack:

1.1 output.filename

This option names the packaged entry js file. The app.js file in the figure below is the packaged entry js file.
Insert picture description here
In a single entry Vue project

Entry file before packaging, configured in vue.config.js

module.exports = {
    
     configureWebpack:{
    
     entry:'./src/main.js', } }

The packaged entry file is configured in vue.config.js

module.exports = {
    
     configureWebpack:{
    
     output:{
    
     filename: 'js/appCS.js' }, } }

Why add a js/ in front, because the js file is generated in the directory specified by the output:path option, and the default is the root directory/.

The packaging result is as follows: in a
Insert picture description here
multi-entry Vue project

Entry file before packaging, configured in vue.config.js

module.exports = {
    
     configureWebpack:{
    
     entry: {
    
     appCS: './src/main.js' }, } }

The packaged entry file is configured in vue.config.js

module.exports = {
    
     configureWebpack:{
    
     output:{
    
     filename: 'js/[name].js' }, } }

[name] is the name of the entry file module

The packaging result is as follows:
Insert picture description here
multiple app.js will be found, this is because configureWebpack uses a merge strategy to configure Webpack.
To remove app.js, use chainWebpack to configure:

module.exports = {
    
     
	chainWebpack: config =>{
    
     
		config.entryPoints.delete('app').end().entry('appCS').add('./src/main.js') 
	} 
} 

The packing result is as follows:
Insert picture description here
1.2 output.chunkFilename

This option names the packaged non-entry js file, then the red box in the figure below is the non-entry js file
Insert picture description here
. Configure in vue.config.js

module.exports = {
    
    
    configureWebpack:{
    
    
        output:{
    
    
            chunkFilename: 'CS.[name].js'
        },
    }
}

The packing result is as follows.
Insert picture description here
However, output.chunkFilename cannot change the name field like chunk-0a4e15c9

1.3 webpackChunkName
webpackChunkName: The name of the block, [request] can be interpreted as the actual parsed file name.
Can be used in routing lazy loading:

function load(component) {
    
    
  return () => import(/* webpackChunkName: "[request]" */ `views/${
      
      component}`)
}

const routes = [
  {
    
    
    {
    
    
      path: '/apiApply',
      name: 'apiApply',
      component: load('api_manage/api_apply'),
    }
  }
]

The packaging result is as follows:
Insert picture description here
src/views/api_manage/api_apply/index.vue The js file generated after this component is packaged is api_manage-api_apply.48227bf7.js.

If you don’t use [request], you can also write like this.

component: () =>import(/* webpackChunkName: "api_manage-api_apply"*/ 'src/views/api_manage/api_apply'),

Looking at other js files again, there are files of the chunk-xxx.js class, as shown in the red box in the following figure.
Insert picture description here
The naming of these js files should be set in the SplitChunks plug-in.

2. SplitChunks plugin configuration options

  • The chunks option determines which modules to extract. The
    default is async: extract only the asynchronously loaded modules and pack them into a file.
    Asynchronously loaded modules: modules loaded by import('xxx') or require(['xxx'],() =>{}).

  • initial: Extract synchronous loading and asynchronous loading modules;
    if xxx is loaded asynchronously in the project and also loaded synchronously, then the xxx module will be extracted twice and packaged into different files.
    Synchronously loaded modules: modules loaded by import xxx or require('xxx').

  • all: modules that are loaded either asynchronously or synchronously are extracted and packaged into a file;

  • minSize option: Specify the minimum size of the extracted module before compression, in bytes; the
    default is 30000, only if it exceeds 30000 bytes will it be extracted.

  • maxSize option: The file size generated by packaging the extracted module cannot exceed the maxSize value;
    if it exceeds, it must be divided and packaged to generate a new file.
    The unit is byte, and the default is 0, which means that the size is not limited.

  • minChunks option: Indicates the minimum number of citations of the module to be extracted, and the number of citations exceeds or equals the minChunks value before it can be extracted.

  • maxAsyncRequests option: the maximum number of on-demand (asynchronous) loads, the default is 6;

  • maxInitialRequests option: When the packaged entry file is loaded, the number of js files (including entry files) that can be loaded at the same time, the default is 4.

    优先级 :maxInitialRequests / maxAsyncRequests < maxSize < minSize;

  • automaticNameDelimiter option: the delimiter of the js file name generated by the package, the default is: ~

  • name option: the name of the packaged and generated js file;

  • The cacheGroups option, the core focus, configure the solution for extracting the module, each item in it represents a solution for extracting the module.
    The following are the unique options in each item of cacheGroups, and the other options are the same as those outside. If each item in cacheGroups is included, it will be configured according to the configuration, and if not, the external configuration will be used;

    • test option: used to match the resource path or name of the module to be extracted, the value is regular or function;

    • priority option: the priority of the scheme, the larger the value, the preferential use of this scheme when extracting the module, the default value is 0;

    • reuseExistingChunk options: true / false.
      When true, if the current module to be extracted exists in the js file that has been packaged and generated, the module will be reused instead of packaging the current module to be extracted to generate a new js file.

    • Enforce option: true / false.
      When true, ignore the options outside minSize, minChunks, maxAsyncRequests and maxInitialRequests

There are many configuration options. The following uses SplitChunks in the actual project to give you a deeper understanding of these configuration options.
First, let's take a look at the default configuration of SplitChunks in Vue Cli3.
Insert picture description here
The default configuration after finishing is as follows:

module.exports = {
    
    
  configureWebpack:config =>{
    
    
    return {
    
    
      optimization: {
    
    
        splitChunks: {
    
    
          chunks: 'async',
          minSize: 30000,
          maxSize: 0,
          minChunks: 1,
          maxAsyncRequests: 6,
          maxInitialRequests: 4,
          automaticNameDelimiter: '~',
          cacheGroups: {
    
    
            vendors: {
    
    
              name: `chunk-vendors`,
              test: /[\\/]node_modules[\\/]/,
              priority: -10,
              chunks: 'initial'
            },
            common: {
    
    
              name: `chunk-common`,
              minChunks: 2,
              priority: -20,
              chunks: 'initial',
              reuseExistingChunk: true
            }
          }
        }
      }
    }
  }
};

Install the webpack-bundle-analyzer plug-in first to visually analyze the packaged files.

npm install webpack-bundle-analyzer --save-dev

Introduce plugins in vue.config.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports={
    
    
  configureWebpack:config =>{
    
    
    return {
    
    
      plugins:[
        new BundleAnalyzerPlugin()
      ]
    }
  }
}

After packaging, it will automatically open http://127.0.0.1:8888/ in the browser, and the content is as follows. You
Insert picture description here
will find a chunk-vendors.js file inside, which is a js file packaged by the vendors in cacheGroups.

You can use the name option to modify the name of the chunk-vendors.js file, the code is as follows:

vendors: {
    
    
  name: `app-chunk-vendors`,
  test: /[\\/]node_modules[\\/]/,
  priority: -10,
  chunks: 'initial'
},

After packaging, you will find that the chunk-vendors.js file has become app-chunk-vendors.js and the contents of the file remain unchanged.
Insert picture description here

3. The entry file for SplitChunks actual combat operation

First remove the scheme in cacheGroups, and then package it.

cacheGroups: {
    
    
 vendors: false,
 common: false
}

Insert picture description here
The two js files app.a502ce9a.js and chunk-be34ce9a.ceff3b64.js are packaged and generated by the entry file main.js in the project.
For example, the app.js file contains element-ui, moment, jquery, vue, router, store, jsencrypt, etc., which are all introduced in main.js.

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import JsEncrypt from 'jsencrypt';
import $ from 'jquery';
import ElementUI from 'element-ui';
Vue.use(ElementUI);
import treeSelect from 'fxft-tree-select';
Vue.use(treeSelect);
import moment from 'moment';
Vue.prototype.moment = moment;
//注册全局变量、全局函数
import base from 'service/base';
Vue.use(base);
//注册打印插件
import print from  'service/print';
Vue.use(print);
const vm = new Vue({
    
    
    router,
    store,
    render: h => h(App)
}).$mount('#app')
window.vm = vm;

There is a piece of code in the index.html generated by the package that is written like this.

<div>
    <div id=app></div>
    <script src=/js/app.a502ce9a.js></script>
</div>

Indicates that app.js is to be loaded at the beginning of the project, which will affect the loading time of the first screen.
Then you can remove some of the introductions that are not used temporarily in the first screen in main.js, for example, these can be removed temporarily.

import JsEncrypt from 'jsencrypt';
import treeSelect from 'fxft-tree-select';
Vue.use(treeSelect);
//注册打印插件
import print from  'service/print';
Vue.use(print);

After packaging, look at the analysis diagram, you will find that jsencrypt and other content have disappeared in app.js.
Insert picture description here
Why is chunk-be34ce9a.js packaged and generated from main.js? Because there is a piece of code in main.js:

//注册全局变量、全局函数
import base from 'service/base';
Vue.use(base);

Looking at the service/base.js file, there are

import('./Export2Excel').then(res => {
    
    
  res.export_json_to_excel(defaultOpition);
})

Export2Excel.js is loaded asynchronously, in service/Export2Excel.js

import {
    
     saveAs } from 'file-saver'
import XLSX from 'xlsx'

Equivalently, file-saver and xlsx are also loaded asynchronously, so file-saver and xlsx will be extracted and packaged to generate chunk-be34ce9a.js files.

In the default configuration, modules loaded asynchronously or indirectly asynchronously in main.js will be packaged separately to generate a js file

What if you want to package all the modules loaded from node_modules into a js file? Vue Cli3 has already done it for us.

cacheGroups: {
    
    
  vendors: {
    
    
    name: `chunk-vendors`,
    test: /[\\/]node_modules[\\/]/,
    priority: -10,
    chunks: 'initial'
  },
}

The core is the test option, which matches the modules loaded by the project from node_modules and extracts and packages the chunk-vendors.js file.
After packaging, I searched for node_modules from the analysis graph, and found that there are still many files containing modules loaded from node_modules, which is not the same as expected.
Insert picture description here
This is the chunks option. The value initial means: if xxx is loaded asynchronously or synchronously in the project how many times, then how many times the module xxx will be extracted and packaged into different files. The core-js library will be loaded into every file in the project, so it will be extracted multiple times.

Just change the value of the chunks option to all (regardless of whether the modules loaded asynchronously or synchronously are extracted and packaged into one file), all modules loaded from node_modules can be packaged into one js file.
Insert picture description here
Insert picture description here
Insert picture description here
It is found that the size of chunk-vendors.js is a bit large, 1.91MB, which is still a js file that needs to be loaded when the project is initialized. Too large will cause the first screen to load too long.
Solution : Use SplitChunks to optimize. For example, to extract the element from chunk-vendors.js, configure it in cacheGroups:

element: {
    
    
  chunks: 'all',
  name: `element-ui`,
  test: /[\\/]element-ui[\\/]/,
  priority: 0,
},

Pay attention to the priority option. To extract the element separately, the value of priority must be greater than the value of priority in the vendors scheme , otherwise it cannot be extracted.

After packaging, you can see that the element is packaged to generate a new element-ui.js file. The size of chunk-vendors.js becomes 1.27MB, which is smaller than the original 1.91MB.
In addition, you can extract third-party dependencies such as xlsx, moment, jquery, etc. by yourself.
Insert picture description here

4. SplitChunks non-entry files for actual combat operations

In the analysis diagram, in addition to the entry file, there are many js files, most of which are generated by the packaged components in the project.

If you use / webpackChunkName: "[request]" / when implementing routing lazy loading , then you can know which component package generated this js file on the js file name generated by component packaging.
Insert picture description here
The
base_info_manage-group_info_set-ability_bind_set.85b419a1.js in the figure is packaged and generated by the view/base_info_manage/group_info_set/bility_bind_set/index.vue component in the project.

base_info_manage-group_info_set-ability_bind_set-edit.08f91768.js is packaged and generated by views/base_info_manage/group_info_set/bility_bind_set/edit.vue in the project.

In addition, you will find: how the content of chunk-5c1416e3.1cbcb0ec.js is similar to the content of base_info_manage-group_info_set-ability_bind_set-edit.08f91768.js, only the content of src/api is missing.
And api/common.js, api/ability_bind_set.js, edit.vue, mixins and other modules have been repeatedly packaged several times.

You can use SplitChunks to extract these modules. Avoid repeated packaging and reduce the overall size of the files generated by packaging.

Configure in cacheGroups:

api: {
    
    
 name: 'api',
 test: /[\\/]api[\\/]/,
 priority: 0,
},

When extracting multiple modules to package and generate files, the name option is required

Insert picture description here
Looking at the analysis diagram after packaging, you will find that api/common.js and api/ability_bind_set.js have been extracted into api.05ad5193.js.
Insert picture description here
Then extract the mixins module and configure it in cacheGroups

mixins: {
    
    
  name: 'mixins',
  test: /[\\/]mixins[\\/]/,
  priority: 0,
},

Insert picture description here
After packaging, look at the analysis diagram and find that the mixins module has been extracted into mixins.8d1d6f50.js.
Insert picture description here
Then extract the edit.vue module and configure it in cacheGroups

base_info_manage: {
    
    
  name: 'base_info_manage',
  test: /[\\/]base_info_manage[\\/]/,
  minChunks: 2,
  priority: 0,
},

Insert picture description here
Among them, the minChunks option must be 2, because from the analysis above, edit.vue is quoted twice, and index.vue is quoted only once.
If it is 1, index.vue will also be extracted;
if it is a value above 2, edit.vue will not be extracted.
Insert picture description here
Insert picture description here
After packaging, look at the analysis diagram and find that the edit.vue module has been extracted into base_info_manage.d5c14c01.js.
If you think the base_info_manage.d5c14c01.js file is too large, there are two ways to deal with it.
Insert picture description here
The first is to use the maxSize option. After extracting the module, the packaged file size cannot exceed the maxSize value. If it exceeds the maxSize value, it must be extracted and packaged to generate a new file.

base_info_manage: {
    
    
    name: 'base_info_manage',
    test: /[\\/]base_info_manage[\\/]/,
    minChunks: 2,
    priority: 0,
    maxSize: 102400
},

After packaging, look at the analysis diagram and you will find that base_info_manage.js has been divided into five small js files.
Insert picture description here
The second method is to continue the extraction according to the subfolders under the base_info_manage folder. For example, there is a subfile called group_info_set under the base_info_manage folder.
Configure in cacheGroups

group_info_set: {
    
    
  name: 'group_info_set',
  test: /[\\/]base_info_manage[\\/]group_info_set[\\/]/,
  minChunks: 2,
  priority: 10,
},

After packaging, look at the analysis diagram and you will find that the group_info_set module collection in base_info_manage.js has been extracted into the group_info_set.js file. The base_info_manage.d5c14c01.js file has also been reduced accordingly.
Insert picture description here
Insert picture description here
In addition, the contents in src/api, src/mixins, and src/service can be combined and packaged to generate a js file, which replaces the mixins.8d1d6f50.js and api.05ad5193.js that were previously packaged and generated

common: {
    
    
  test: /[\\/]api[\\/]|[\\/]mixins[\\/]|[\\/]src[\\/]service[\\/]/,
  priority: 0,
  name: 'common',
},

Insert picture description here

Not much else to say, you can use the SplitChunks plug-in to control Webpack to package and generate the js files you want in your own project as mentioned above, until each js in the dist/js folder is the js you expected to generate File so far.

5. Summary

The essence of using the SplitChunks plug-in to control the content of the js files generated by Webpack packaging is to prevent modules from being repeatedly packaged, split over-large js files, and merge scattered js files.
The ultimate goal is to reduce the size of requested resources and the number of requests. Because the two are contradictory, it is necessary to use the SplitChunks plug-in according to the actual situation of the project, and remember the golden mean.

Guess you like

Origin blog.csdn.net/ZYS10000/article/details/113144217