1. Why code separation

In single-page or multi-page applications, code separation can optimize performance.

For example, splitting asynchronously loaded code into a separate chunk and loading it on demand when it needs to be called (for example, at Click) can reduce the size of the first screen of code, thus increasing the first screen load speed.

In addition, in our project, we may use a lot of third party libraries (such as LoDash, RXJS, etc.), and the code of these third party dependencies usually changes very little. Therefore, it is a good idea to separate the third party dependencies into a package and include hash in the package name (webPack can easily do this). The advantage of this is that it can be combined with browser HTTP caching mechanisms, such as max-age, to achieve a long cache of related resource bundles, thus optimizing performance.

Common scenarios for code splitting are:

  • Separate business code from third-party dependencies
  • Separate first – and asynchronously loaded code
  • Separate the business code from the common code of the business

2. Install dependencies

Index.html is automatically generated by html-webpack-plugin

npm install -D html-webpack-plugin
npm install -D webpack // html-webpack-plugin relies on webpack
npm install --save axios lodash
Copy the code

3. Directory structure

// '--' represents directory, '-' represents file
  --demo09
    --src
      -app.js
      -async-module1.js
      -async-module2.js
      -module.js
    -index.html
    -webpack.config.js
Copy the code

src/async-module1.js

export const data = 'this is async module1';
Copy the code

src/async-module2.js

export const data = 'this is async module2';
Copy the code

src/module.js

export const sayHello1 = (a)= > {
  console.log('Hi I want to say hello1');
}

export const sayHello2 = (a)= > {
  console.log('Hi I want to say hello2');
}

export const sayHello3 = (a)= > {
  console.log('Hi I want to say hello3');
}
Copy the code

src/app.js

import { sayHello1, sayHello2, sayHello3 } from './module';

sayHello1();
sayHello2();
sayHello3();


// Load async-module1 asynchronously
setTimeout((a)= > {
  require.ensure(
    [],
    function () {
      const asyncModule = require("./async-module1");
      console.log(asyncModule.data);
    },
    "module1"
  );
}, 3000);

// Load async-module2 asynchronously
setTimeout((a)= > {
  require.ensure(
    [],
    function () {
      const asyncModule2 = require("./async-module2");
      console.log(asyncModule2.data);
    },
    "module2"
  );
}, 3000);


// Reference third-party libraries
// https://github.com/lodash/lodash
import * as _ from "lodash";
// https://github.com/axios/axios
import * as axios from "axios";

console.log(_);
console.log(axios);
Copy the code

3. Configure rules for packaging third-party libraries

SplitChunks with webpack4 is easy to do.

See my article Demo08 on SplitChunksPlugin for details on how to use the various parameters of splitChunks

   splitChunks: {
      cacheGroups: {
        vendors: {
          chunks: "all".// Use all mode
          test: /[\\/]node_modules[\\/]/.// Matches the module under node_modules
          name: "vendors".// Package name, the final name should be combined with output chunkFilename
          minChunks: 1.minSize: 30000.priority: 10 // Set the priority}}}Copy the code

4. Configure rules for packaging asynchronous loading packages

Package asynchronous load packages

   splitChunks: {
      cacheGroups: {
        async: {
          chunks: "async".minChunks: 1.// The minimum number of times a code block has been referenced
          maxInitialRequests: 3.// Set the maximum number of requests
          minSize: 0.// Set the minimum size of each chunk (default 30000) to 0 for testing purposes
          automaticNameDelimiter: '~'.priority: 9}}},Copy the code

5. Complete WebPack configuration file

const path = require("path");

module.exports = {
  mode: 'development'.In production mode, [name] is converted to 0, 1, 2...
  entry: {
    app: "./src/app.js",},output: {
    publicPath: __dirname + "/dist/".// References to packaged resource files will be based on this path
    path: path.resolve(__dirname, "dist"), // The packaged output directory
    filename: "[name].[chunkhash].bundle.js".// Each package contains chunkhash
    chunkFilename: "[id].[chunkhash].chunk.js"
  },
  optimization: {
    runtimeChunk: "single".splitChunks: {
      cacheGroups: {
        async: {
          chunks: "async".minChunks: 1.// The minimum number of times a code block has been referenced
          maxInitialRequests: 3.// Set the maximum number of requests
          minSize: 0.// Set the minimum size of each chunk (default 30000) to 0 for testing purposes
          automaticNameDelimiter: '~'.priority: 9
        },
        vendors: {
          chunks: "all".// Use all mode
          test: /[\\/]node_modules[\\/]/.// Matches the module under node_modules
          name: "vendors".// Package name, the final name should be combined with output chunkFilename
          minChunks: 1.minSize: 30000.priority: 10 // Set the priority}}}}};Copy the code

5. Run the package command

(You have global Webpack and webPack-CLI installed by default)

webpack
Copy the code

After successful packaging, the output is in the dist directory of Demo09

(Note that “mode” is set to “development”)

app226.A343cb53e0a689358. The chunk. Js (app) main moduleasync~module187.d116fd41640c30a6b2.chunk.js (async- module1 module)async~module265866.f4d15253512c981.chunk (async- Module2 Module) Runtime.4e6De616bd3030f8bff8. Bundle. Js (webpack runtime modules) vendors. A83c085b3a7ac03b1b47. The chunk. Js (third party relies on module)Copy the code

6. Modify the program code to verify the packaging results

You can change the app. The js code, such as run a webpack command again, you will find that a third party based on module package name has not been changed: vendors. A83c085b3a7ac03b1b47. The chunk. Js.

Run dist/index.html in a browser and open the console to see the effect of asynchronously loading the module.

(note: the runtime. XXXXXXXX. Bundle. Js module contains references logic for induction load module, in addition, the asynchronous loading reference relative path from the output – > publicPath configuration)

7. Source address

Demo code address: github.com/SimpleCodeC…

Warehouse code address (and directory): github.com/SimpleCodeC…