First, first things first:

Webpack4 is coming out next month, CommonsChunkplugin is dead!

Chunk

If you’re still interested, come and see it.

Let’s start by figuring out what a chunk is: WebPack calls a chunk a collection of code packaged together with multiple modules.

There are three types of Chunks in Webpack:

  1. Entry Chunk: a collection of module codes containing WebPack Runtime codes.
  2. Normal chunk: a collection of modules that do not contain Runtime code.
  3. Initial chunk: A special type of normal chunk, according to the document. It will load before Normal Chunk (for those of you who are interested).

A few other points to note:

  1. Entry Chunk must be loaded before Normal chunk, because it contains runtime code that defines a list of functions that WebPack needs to use. If it is not loaded first, the rest of the code webpack cannot play.
  2. Each entry point generates an entry chunk.
  3. For each module lazily loaded with import(), a normal chunk will be generated. This chunk will depend on the entry chunk called import() as its child.

CommonsChunkPlugin

First post a section of their own official website introduction:

The CommonsChunkPlugin is an opt-in feature that creates a separate file (known as a chunk), consisting of common modules shared between multiple entry points. By separating common modules from bundles, the resulting chunked file can be loaded once initially, and stored in cache for later use. This results in page speed optimizations as the browser can quickly serve the shared code from cache, rather than being forced to load a larger bundle whenever a new page is visited.

Webpack-packed code is stored as chunks. The CommonsChunkplugin, however, takes the same modules from different chunks and places them in a common chunk. This public chunk only needs to be downloaded once, and all chunks can use it. And this part of the code can be placed in the cache, so that you do not need to download later (there is also an article about using Webpack to do cache, if you are interested). There’s also less code per chunk, so each load is faster.

How to use CommonsChunkplugin?

Common parameters:

1. Determine the parameters for generating chunk: name, Names, async

Name: string: indicates the name of the public chunk. If an existing chunk name is passed in, that chunk is used as a public chunk to hold the extracted common code. Otherwise, Webpack creates a new public chunk.

Names: string[]: The same as name, but passed in an array. It’s like doing a code cut for each element in the array.

Async: Boolean | string: the common code to extract a chunk, lazy loading is used to download, then when the incoming value to a string, the value will be used as lazy loading the chunk name. Currently, this is usually done with children (Entry chunks are loaded when the app is initialized, so adding async tags doesn’t make sense).

2. Decide on chunks: chunks, children, and deepChildren to be extracted

Chunks: string[]: Webpack will fetch common code from incoming chunks or, if not, from all entry chunks. Children: Boolean: when children(deepChildren) is not set, webpack extracts common code from entry chunk based on conditions. When children is set to true, Webpack extracts the code from the direct sub-chunks of the entry chunk. DeepChildren: Boolean: Same as children, but selects all sub-nodes of the common chunk.

3. Determine extraction conditions: minChunks

minChunks: number|infinity|function(module,count)->boolean: Passing a number or infinity(the default is 3) tells WebPack that the module will only be extracted if the number of module repeats is greater than or equal to that number. When the input is a function, all the modules in the eligible chunk will be passed into the function for calculation, and the modules that return true will be extracted to the target chunk.

Long winded a lot, to sum up:

  • In webpack, there are two types of chunks: entry chunk and normal chunk. If you want to extract common chunks in normal chunk without setting them manually, set children(deepChildren) to true. Otherwise, the chunk is an Entry chunk. If you are not satisfied with the webpack categories, use chunks to manually specify the chunks to be selected.
  • Set async to true if you want to do lazy loading of packaged public chunks.
  • MinChunks are used to determine which modules to extract into the common chunk

Here are a few more examples:

case 1

Two entry apps and page1 use react, react-dom and classnames. We need to extract modules that appear twice or more into a common chunk vendor: App:

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import * as axios from 'axios';
import * as classnames from 'classnames';
Copy the code

Page1:

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import * as classnames from 'classnames';
Copy the code

Webpack configuration:

new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    minChunks: 2,
}),
Copy the code

case 2

Continuing with the case1 example, we can see that the axios package is still mixed up with the app’s business code. Pull him out again:

new webpack.optimize.CommonsChunkPlugin({
    name: 'axios',
    chunks: ['app'],
    minChunks: function(module) {
        return/axios/.test(module.context); }}),Copy the code

Of course, this is for the purpose of writing examples of chunks, so you don’t have to do this twice in practice. Just type all the libraries in node_modules into vendor for the first fetch (minChunks: 1 is ok)

case 3

If the sub-chunk exists, here I choose to extract the sub-chunk into a new lazy chunk: App asynchronous reference Home, Topics, About:

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import * as moment from 'axios';
import * as classnames from 'classnames';

const Home = () => import('./Home');
const Topics = () => import('./Topics');
const About = () => import('./About');
Copy the code

Home,Topic, and About all reference Mobx and moment

import * as React from 'react';
import * as moment from 'moment';
import * as mobx from 'mobx';
Copy the code

new webpack.optimize.CommonsChunkPlugin({
    name: 'app',
    async: 'vendor',
    children: true,
    minChunks: 2,
}),
Copy the code

As shown in the figure, it is equivalent to telling Webpack to scan the modules in the direct sub-chunks (Home, Topics, About) of app(Entry Chunk) and extract the modules that appear more than 2 times and put them into a lazy loading module named Vendor.

case 4

In addition to extracting common modules, the CommonsChunkPlugin is also very useful for front-end engineering code cutting. To make better use of the cache, suppose we have the following requirements:

  1. Webpack Runtime (Entry Chunk) : As mentioned above, the Runtime code must be executed before any other code. And since the Runtime code changes frequently with module and chunk IDS, it is recommended to package it separately

  2. Lib (Normal chunk): Lib contains basic libraries such as react, react-dom, and react-router that will not change.

  3. Vendor (Normal Chunk): Vendor hosts a library of tools like Axios, Moment, and others that change occasionally

  4. Normal Chunk: Changes at any time, a separate chunk

Direct configuration:

        new webpack.optimize.CommonsChunkPlugin({
            deepChildren: true,
            async: 'async-vendor',
            minChunks: function (module) {
                return /node_modules/.test(module.context);
            }
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: function (module) {
                return /node_modules/.test(module.context);
            }
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: "lib",
            minChunks: function (module) {
                return /react/.test(module.context);
            }
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'manifest',
            minChunks: Infinity
        }),
Copy the code

First packing: Extract the common module (MOBx, moment) from the direct sub-chunks (Home,Topics,About) of all Entry Chunks (app, page1) and put it into lazy loading chunk async-vendor.

Second packaging: Extract the modules in node_modules from all entry chunks (app, page1) and put them into chunk vendor. App, page1 now becomes normal chunk.

Third packaging: Extract modules with react paths from all entry chunks (vendor) and place them in chunk lib.

Fourth packaging: Create a manifest chunk without any modules (minChunks: Infinity). Since the MANIFEST is the only chunk of entry at this point, the Runtime code goes into the Manifest.

As shown, the business code is completely separated from the lib code, vendor tool code, and so on.

reference

CommonsChunkPlugin

Code Splitting

Vendor and code splitting in webpack 2

webpack: Unraveling CommonsChunkPlugin

webpack bits: Getting the most out of the CommonsChunkPlugin()

Added deepChildren support from ArcEglos’ pull request