current position:Home>Webpack practice: increase the loading speed of a library by four times

Webpack practice: increase the loading speed of a library by four times

2021-08-26 00:36:35 toln

Project background

The project is a library used within the company , Use webpack package .(webpack edition : 5.40.0) It used to be using npm Package management in the form of , However, due to the large volume of the project after packaging , Affect the loading speed of the page , So I decided to give up npm Package management , Pack it into js file , adopt script Tag to reference . about npm Package and js file , Each has its own advantages and disadvantages .

type advantage shortcoming
npm package Easy to do version management ; The citation method is simple Cannot split when package size is too large ; Difficult to do load optimization
js file Easy to split modules , Do load optimization ; High citation flexibility Version management is cumbersome ; The caller needs to choose the right time to load js file

Because it is an internal package , And higher requirements for loading performance , So you can use js The way

Optimization steps

One 、 Dynamically import some modules

Some modules that are not necessarily used in the project and are relatively large , use webpack Reference by dynamic import in , This reduces the first loaded package volume . For example, before modification :

import module1 from './module1';
 Copy code 

After modification :

//  Here we will use module1 object 
const module1 = await import(
   /* webpackChunkName: "module1" */ './module1'

 Copy code 

such webpack Will module1 Pack it up as a stand-alone js file . The file will only be loaded when you import it .

webpack It also supports Pre acquisition module , Is to load when the browser is idle , Instead of loading when you introduce . It's practical to <link> label rel Property preload and prefetch value .

Two 、 Module split

The previous method is only applicable to modules that will not be used immediately , But for some core modules, this method cannot be used . For example, in our project three.js, The volume of the module is also relatively large , Can pass webpack To configure optimization Package it into a separate js file ,

// ...
optimization: {
    // ...
    splitChunks: {
      cacheGroups: {
        three: {
          test: /[\\/]node_modules[\\/](three)[\\/]/,
          name: 'three',
          chunks: 'all',
          priority: 2,
 Copy code 

Other larger modules can also be separated .

3、 ... and 、 Modify the module export method

The first two steps are mainly to split the module , The purpose is to realize delayed loading and parallel loading , This basically increases the loading speed

Now we need to modify the export mode of the module . use npm Package management is actually a process after packaging CommonJS module, Internal use module.exports = myLibrary export , And then use require('myLibrary') Mode introduction . Now pack it up as a js Files are imported directly in the browser , So we need to myLibrary Expose to global objects .( You can also use it AMD Or other browser supported module Syntax , But these methods are not used at present ), take webpack Of output.library.type from commonjs Change it to umd:

library: {
  name: 'myLibrary',
  type: 'umd',

 Copy code 
Four 、 Deploy js file

We need to deploy the packaged product to the static server . To configure webpack Of publicPath:

// ...
output: {
  path: path.resolve(__dirname, 'dist'),
  publicPath: ``,
 Copy code 

After each package dist Upload the directory to the server path Next . We are currently using gitlab Of CI/CD Complete automated deployment .

5、 ... and 、 Call... In a new way

Use dynamic loading script The way , The following is the loading function :

function loadScript(src) {
  return new Promise((resolve, reject) => {
    const scriptEle = document.createElement('script');
    scriptEle.type = 'text/javascript';
    //  Dynamic scripts async The default is true,  Set to false In order to execute ( Parallel loading )
    scriptEle.async = false;

    if (scriptEle.readyState) {
      // IE
      scriptEle.onreadystatechange = () => {
        if (scriptEle.readyState == 'loaded' || scriptEle.readyState == 'complete') {
    } else {
      scriptEle.onload = () => {
      scriptEle.onerror = () => {
        reject(`The script ${src} is not accessible`);

    scriptEle.src = src;
      document.currentScript.parentNode.insertBefore(scriptEle, document.currentScript);

 Copy code 

Parallel loading and sequential execution are used , The order of execution is :

Runtime files --> Separated dependencies --> Master file

6、 ... and 、 Better use of cache

Use the hash value as the packaged file name , To ensure that the cache becomes invalid after modifying the file .

 output: {
    // ...
    filename: '[name].[contenthash].js',
 Copy code 

It should be noted that , When we modify one of the files , The hash value of the packaged product corresponding to other files can also be changed .

for instance , Suppose there are three modules in the project and they are all packaged into three separate modules js file , Module dependencies are as follows :


When we changed module1, We only expect module1 Corresponding js File name hash value changed . In fact, the file names of these three files have changed . The reason is that we didn't package the runtime files separately , Changing the file name of one file will change the content of another file , Form a chain reaction . Use the following configuration :

optimization: {
    runtimeChunk: 'single',
 Copy code 

In this way, a separate runtime file will be generated after packaging , This file also needs to be deployed and loaded ( Execute before executing other files ).

So we're modifying module1, Only module1 Corresponding js The name of the file and the runtime file has changed , To optimize the cache .

copyright notice
author[toln],Please bring the original link to reprint, thank you.

Random recommended