The Spring Festival of 2020 has passed. I had planned to go back to Zhengzhou, but because of the novel Coronavirus pneumonia outbreak, the company postponed my work time. I also postponed my trip to Zhengzhou to stay at home with my baby for a few days. In the past, I learned to write blog in my study. Today, I am very special, holding my computer in my arms, sitting on the roof in the sun, and writing blog with my family.

In this article, I will share with you how to implement code sharding in WebPack.

In current engineering projects, one of the important points to achieve high-performance applications is to let users only load necessary resources at a time, and the resources with low priority are gradually loaded and acquired by lazy loading and other technologies.

One of the techniques unique to Webpack as a packaging tool is code sharding, which allows you to break up code into specific forms, using on-demand resources, rather than loading it all. Code sharding can effectively reduce the size of resources loaded on the first screen, but at the same time, we are faced with other problems, such as how to fragment project modules and how to manage resources after sharding. Today we need to analyze and solve these problems.

Use entry to partition code

In Webpack, each entry in the configuration parameters will generate a corresponding resource file, through the entry configuration we can do some simple and effective code splitting.

Third party libraries and tools that are often introduced in a project and don’t normally change can be placed in a single portal, where resources are not updated frequently, so that clients can effectively cache these resources so that users don’t have to reload every time they request a page.

//webpack.config.js
entry: {
	index: './index.js'.lib: ['lib-1'.'lib-2']}//index.html
<script src="dist/lib.js"></script>
<script src="dist/index.js"></script>
Copy the code

This split approach works best for libraries that bind interfaces to global objects, because modules in business code cannot directly reference modules in the library, which belong to different dependency trees.

For multi-page applications, we can use entry partitioning to split the code. For example, create an entry for each page and put in code that only touches that page, and create another entry to contain all the common modules and have each page load. But this still creates the problem of public modules being in a different dependency tree from business modules. In addition, many times not all pages require these common modules. This requires us to use webPack-specific plug-ins to solve this problem.

CommonsChunkPlugin

CommonsChunkPlugin is a built-in plugin before webpack4 and SplitChunks after webpack4. CommonsChunkPlugin is mainly used to extract third-party libraries and public modules to avoid the loading time of bundles loaded on the first screen or bundles loaded on demand being too large. It is a powerful tool for project optimization.

Advantages:

  • Reduce the repetitive module packaging in the development process, which can improve the development speed;
  • Reduce the overall resource volume;
  • Properly sharded code can make better use of client caching. The first page also illustrates through a simple example, assuming that there are two entry files a.js and B. js in our current project, and react is introduced, the following is the configuration without CommonsChunkPlugin
//webpack.config.js
module.exports = {
	entry: {
		a: './a.js'.b: './b.js'
	},
	output: {
		filename: '[name].js'}}//a.js
import React from 'React'./ / to omit

// b.js 
import React from 'React'./ / to omit
Copy the code

React is packaged into A.js and B.js, respectively, according to the resource volume.

Change webpack.config.js to add CommonsChunkPlugin configuration

const webpack = require('webpack');
module.exports = {
	entry: {
		a: './a.js'.b: './b.js'
	},
	output: {
		filename: '[name].js'
	},
	plugins: [
	new webpack.optimize.CommonsChunkPlugin({
	name: 'commons'.filename: 'commons.js'}})]Copy the code

The Webpack is introduced in the header of the configuration file, then an instance of the plug-in is created using its internal CommonsChunkPlugin function, and the configuration object is passed in as the configuration parameter

  • Name: Specifies the name of the public chunk
  • Filename: after the extracted resource filename is packed, you can see that Commons. Js is added to the generated resource, and the size of a.js and b.js files is reduced. This is because react and dependent modules are added to Commons. It is important to note, however, that we need to import the common commons.js file before introducing any other js to the page.

In terms of extracting common modules, the CommonsChunkPlugin can meet the needs of many scenarios, but it has some shortcomings. 1) One CommonsChunkPlugin can only extract one vendor. If we want to extract multiple vendors, we need to configure multiple plug-ins, which will increase a lot of repeated configuration codes.

2) The manifest mentioned earlier actually causes the browser to load one more resource, which is not friendly to page rendering speed.

3) Due to some defects in internal design, CommonsChunkPlugin will destroy the dependency of modules in the original Chunk when extracting common modules, making it difficult to carry out more optimization. For example, in an asynchronous Chunk scenario the CommonsChunkPlugin does not work as expected.

optimization.SplitChunks

Optimization.splitchunks (SplitChunks for short) is a code sharding feature redesigned and implemented by Webpack 4 to improve the CommonSchunk-Plugin. Not only is it more powerful than the CommonsChunkPlugin, it’s also simpler to use.

The configuration file web pack.config.js is:

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  context: path.join(__dirname, './src'),
  entry: {
    index: './index.js'
  },
  output: {
    // path: path.join(__dirname, 'dist'),
    filename: 'index.js'.publicPath: '/dist/'
  },
  mode: 'development'.optimization: {
    splitChunks: {
      chunks: 'all'}},module: {
    rules: [{test: /\.css$/i.use: ['style-loader', {
          loader: 'css-loader'.options: {
            modules: {
              localIdentName: '[path][name]__[local]--[hash:base64:5]',}}}]}, {test: /\.js$/.exclude: /(node_modules|bower_components)/.use: {
          loader: 'babel-loader'.options: {
            cacheDirectory: true.presets: [['env', {
                  modules: false}]}}}],}}Copy the code

The two index.js files and index2.js files need to be introduced

// index
import index2 from  './index2.js';
import React from 'react'
document.write('index.js', React.version);

//index2
import React from 'react'
document.write('index2.js', React.version);


Copy the code

Use optimization.splitchunks to replace the CommonsChunkPlugin and specify the value of the chunks as all. The implication of this configuration item is that splitChunks will apply to all chunks (by default, SplitChunks only apply to asynchronous chunks and do not need to be configured.

Originally the result was supposed to be index.js, but due to SplitChunks, it generated vendors~index.index.js and extracted react into it. The running effect is as follows:

SplitChunks are extracted by default:

  • The extracted chunk can be shared or come from the node_modules directory. This one is easy to understand; modules that are referenced multiple times or in node_modules tend to be generic modules and are better suited to be extracted.
  • The extracted Javascript chunk size is larger than 30kB (before compression and gzip), and CSS chunk size is larger than 50kB. This is also easy to understand. If the volume of extracted resources is too small, the optimization effect will be relatively general.
  • During the loading on demand process, the maximum value of resources in parallel requests is less than or equal to 5. Loading on demand refers to loading scripts by dynamically inserting script tags. We generally don’t want to load too many resources at the same time, because each request costs the establishment and release of links, so the extraction rules only take effect when there are not many parallel requests.
  • During the first load, the maximum number of resources in parallel requests is less than or equal to 3. This is similar to the previous tip, except that the performance requirements are often higher when the page first loads, so the default threshold is lower.

SplitChunks extraction mode

The default extraction method of SplitChunks is asynchronous extraction. When the value of “ALL” is set on the chunks, non-asynchronous resources can be extracted.

SplitChunks configuration

optimization: {
    splitChunks: {
      chunks: 'async'.minSize: 30000.minRemainingSize: 0.maxSize: 0.minChunks: 1.maxAsyncRequests: 6.maxInitialRequests: 4.automaticNameDelimiter: '~'.name: true.automaticNameMaxLength: 30.cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/.priority: - 10
        },
        default: {
          minChunks: 2.priority: - 20.reuseExistingChunk: true}}}}Copy the code

(1) Matching mode Through chunks, we can configure the working mode of SplitChunks. It has three optional values, async (the default), INITIAL, and all. Async means that only asynchronous chunks are extracted. Initial takes effect only on incoming chunks (if initial is configured, asynchronous is invalid). All means that both modes are enabled at the same time.

(2) Matching conditions minSize, minChunks, maxAsyncRequests, and maxInitialRequests are all matching conditions.

(3) the name configuration item defaults to true, which means that SplitChunks can be automatically named for newly generated chunks based on cacheGroups and scope, separated by automaticNameDelimiter. Vendors ~a~b~c. JS means cacheGroups are vendors, and the chunk is generated by three entry chunks, VENDORS ~ A ~ B ~ C.

(4) cacheGroups can be understood as rules for separating chunks. By default, there are two rules — defaultVendors and Default. DefaultVendors extract all eligible modules from node_modules, and default acts on modules that are referenced multiple times. We can add or modify these rules, and if we want to disable a rule, we can set it to false. When a module qualifies for more than one cacheGroups, it is prioritized based on its Priority configuration item.

conclusion

A few ways to implement code sharding for WebPack: plan your entries properly, use Commons-chunkPlugin or SplitChunks, and share them here for now

Finally, we remind you to wear masks, wash your hands frequently, try not to go out as much as possible, take preventive measures and stay away from the Coronavirus.