Chemical reactions of splitChunks and import modes

preface

Webpack unpacking is a common tool for performance optimization. Before WebPack 4, CommonsChunkPlugin was used for this optimization, but after WebPack 4, SplitChunksPlugin replaced it.

SplitChunksPlugin has a default configuration right out of the box on webpack’s official website, but the default configuration is not necessarily suitable for our business:

  • The newchunkCan be shared, or modules fromnode_modulesfolder
  • The newchunkVolume is greater than the20kb(in themin+gzPrevious volume)
  • When chunks are loaded on demand, the maximum number of parallel requests is less than or equal to30
  • The maximum number of concurrent requests is less than or equal to when the initialization page is loaded30

In fact, the configuration also depends on how the developers themselves use it: casual developers prefer global import, while compulsive developers prefer dynamic import. Different import methods for the same configuration will also lead to different packaging results.

The following content is the experimental procedure, mainly studying the Chou between minSize and minChunks and the introduction mode.

To prepare

The environment that

The current environment and version are as follows. The test project is empty VUE2 project and a single entry project

  • window x64
  • nodeVersion:12.12.0
  • webpack:4.46.0
  • vue:2.6.14

Vue.config. js Configuration description

The vue.config.js file is configured as follows, and the webpack-bundle-Analyzer dependency needs to be installed in advance.

// vue.config.js
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer")
module.exports = () = > ({
  configureWebpack: config= > {
    if (process.env.ENV === "analyze") {
      // Manually configure the NPM command
      config.plugins.push(
        // Use the packaged analysis plug-in
        new BundleAnalyzerPlugin({
          analyzerHost: "localhost".analyzerPort: "8182"}}})),chainWebpack: config= > {
    config.when(process.env.NODE_ENV === "production".config= > {
      // Unpack to reduce the size of the initial loading vendor file and reduce the first screen events
      config.optimization.splitChunks({
        / / configuration options related to see's official website: https://v4.webpack.docschina.org/plugins/split-chunks-plugin/
        // The configuration here is for all cache groups
        chunks: "all".// For all code blocks
        minSize: 10000.// The minimum chunk size to extract
        maxSize: 0.minChunks: 1.// Minimum number of references
        maxAsyncRequests: 5.maxInitialRequests: 3.automaticNameDelimiter: "~".automaticNameMaxLength: 30.name: true.cacheGroups: {
          // Separate large packages to reduce vendor size and speed up the first screen
          vendors: {
            name: "chunk-vendors".// Enforce cannot set name directly if the default value is false. Otherwise, packaging will fail
            test: /[\\/]node_modules[\\/]/,
            priority: -10.// Indicates the priority of the cache.
            enforce: true}}})})Copy the code

The NPM command is configured to facilitate analysis

// package.json
"scripts": {
  "analyze": "set ENV=analyze&&vue-cli-service build"
}
Copy the code

File structure

The file structure is as follows. The file used for testing is test.vue, which is about 14KB in size. This is why the minSize value of the configuration item above is 10000 (content is not important, “large” is ok 😃).

| -. Vscode cover vscode configuration | -- -- SRC | | - components global components/third party components | | -- the Helloworld. Vue | | -- test. Vue components, the introduction of global/local 14 KB size material | | - views | | - Home page 1 | | - the About page 2 | | - Datt page | 3 | -- app. Vue entry file | -- vue. Config. Js vue packaging configuration fileCopy the code

Routing structure

Note the routing, which requires a chunkName for the file

const routes = [
  {
    path: "/".name: "Home".component: Home
  },
  {
    path: "/about".name: "About".component: () = > import(/* webpackChunkName: "about" */ ".. /views/About.vue")}, {path: "/datt".name: "datt".component: () = > import(/* webpackChunkName: "datt" */ ".. /views/datt.vue")}]Copy the code

If you don’t want to manually ,,,,,github.com/Real102/vue…

Open is dubious

Scenario 1: Global import

First, let’s test the situation of global introduction. I guess many gyMs often do this kind of thing. After all, it is convenient and quick.

The configuration items are slightly synchronized and the other items remain unchanged. Note that mixSize should be smaller than test.vue volume (and larger than HelloWorld.vue volume)

config.optimization.splitChunks({
  minSize: 10000.minChunks: 1
})
Copy the code

Run the NPM run analyze command, which automatically opens the http://localhost:8182/ page as follows:

Chunk-vendor has been hidden (and hidden later) to make it look comfortable. Next, leave the parsed page and temporarily cancel the global import of test.vue and run again:

By comparing the above two figures, the volume difference between app.js with global introduction and without introduction is approximately equal to the volume of test.vue (the actual volume difference is 12.79KB, less than the volume of test.vue *, the specific reason can be seen below), so it can be inferred that, Test.vue is actually packaged into app.js (instead of generating a separate chunk).

GYM, if you are interested, can test the test. Vue package path problem if minSize, minChunks or both are not satisfied. It should be packaged into app.js (if it does not meet the criteria, it will not be unpacked, it will be packaged into app.js)

Scenario 2: Partial introduction of non-home pages

(datt.vue, datt.vue, datt.vue, datt.vue, datt.vue, datt.vue, datt.vue, datt.vue

First, change the configuration conditions so that test.vue only meets the minSize condition. Run the analysis command:

config.optimization.splitChunks({
  minSize: 10000.minChunks: 3 // The current number of references does not meet the requirement of 3
})
Copy the code

Before we start analyzing, let’s change the configuration conditions so that test.vue only meets the minChunks condition. Run the analysis command:

config.optimization.splitChunks({
  minSize: 30000.minChunks: 1 // The current number of references does not meet the requirement of 3
})
Copy the code

Now you can compare the above two pictures and find the following two problems:

  1. Only meetminSizeConditions,test.vueWas unpacking
  2. Only meetminChunksConditions,test.vueAre packed separately toabout.vuedatt.vue
  3. test.vueThe volume of the for12.8 KB

If unpacking conditions are not met, WebPack will merge the referenced components into the chunk where the source file belongs. This should be fine

The volume of test.vue is 12.79KB. Compared with the volume difference in scenario 1, it is almost the same (12.79KB and 12.8KB). As for why it is not 14KB, I guess it is caused by webpack/terserPlugin compression

Finally, let’s take a look at the first problem. I re-tested the chunks with 13 or even 30 under the minSize condition and found that the test.vue was still unpacked. Many gyMs may believe that they need to meet both conditions before unpacking, including me (until I did this experiment…).

Knock on the blackboard!! Knock on the blackboard!! Knock on the blackboard!!

In fact, the above situation is related to the chunks. Chunks can take three values: Initial, async, and all, which respectively represent the objects to be unpacked: the code blocks required for the home page, the code blocks introduced on demand, and all code blocks. I will not write the process here. If you are interested, you can test it yourself, and control the two variables minSize and minChunks. Here are my own tests:

  1. chunks = initial: Cut only the code needed for the home page.node_modulesWill be packed tochunk-vendor.js(if configured), all other required modules are packagedapp.jsAnd code that is not required for the home page,Even if it does, it won’t be extracted
  2. chunks = async: Cuts only for code loaded on demand.node_modulesAnd other code needed for the home page will be packagedapp.js(even if configured), rather than the other code required for the home page,As long as meetminSizeIf the number of references is greater than 1, it will be extracted
  3. chunks = all: Cuts for all code. The first step is to followcacheGroupsThe code that needs to be used on the home page will be packaged intoapp.js, other code that is not required for the home page,As long as meetminSizeIf the number of references is greater than 1, it will be extracted

Scenario 3: Partial introduction of the home page

Test. vue and about.vue are two files introduced on the home page.

Once again, change the configuration parameters so that both conditions are met and restore chunks to ALL:

config.optimization.splitChunks({
  chunks: "all".// Restore to all
  minSize: 10000.minChunks: 1
})
Copy the code

As you can see from the figure above, test.vue is packaged into app.js rather than extracted. Thus, it can be seen that it is more impossible to extract when the conditions are not met.

Come to a conclusion

At this point, it should be clear what the chemistry is between minSize, minChunks, and import modes.

In general, we cut all code blocks. For Async, the home page is not processed, and for INITIAL, other non-home page modules are not processed. GYM can try

The following conclusions are also mainly for the consequences of chunks = all:

  1. Any code blocks that are introduced globally will be incorporatedapp.jsTherefore, it is necessary to carefully consider which needs to be introduced globally and which needs to be introduced locally (distinguish whether the home page needs to be introduced or not).
  2. Code blocks that need to be imported on the home page, whether local or global, will be merged intoapp.jsin
  3. Code blocks introduced on demand can be considered globallyminSizeminChunks(Too much extraction of common code leads to an increase in requests, and conversely, decreases in requests, but increaseschunkTherefore, it is necessary to consider both performance and cost.

Write in the last

The above is all the experimental content. If you are interested in async, INITIAL, multi-entry project, etc., you may be surprised 😎~

The test code is relatively simple, it is recommended to optimize according to the actual project. Once the idea is grasped, implementation is not difficult

If you have any questions about the above content, please feel free to comment

I am a husband, you can call me qi Ye