Webpack is a static module bundler for modern JavaScript applications. When WebPack works with an application, it recursively builds a Dependency graph containing every module the application needs, and then packages all of those modules into one or more bundles.

Webpack is a big contributor to the evolution of front-end engineering to where it is today. Project engineering brings a lot of convenience. We no longer need to handle the relationship between dependencies manually, and we can use more convenient frameworks. We can pay more attention to the business itself and focus on building our products.

Using lazy loading or loading on demand in WebPack is a great way to optimize a web page or application. In this way, your code leaves at some logical breakpoint, and then references, or is about to reference, new blocks of code as soon as you have done something in those blocks. This speeds up the initial loading of the application and reduces its overall size, since some code blocks may never be loaded.

So let’s explore what WebPack does with lazy-loaded modules

To realize the background

Let’s assume we’re working on a real project with upload and download capabilities.

The download function usually opens a link, so we implemented it directly in the main package. While the upload function may use a third party SDK, we used lazy loading for loading. Only when the user clicks upload, we load the package with upload capability to upload.

The upload and download feature may use some third-party SDKS, which tend to be quite large, and this feature makes sense as a lazy loading implementation.

To demonstrate the difference, we’ll make a distinction between “download” and “upload.”

Basic Project Configuration

Let’s build a basic WebPack configuration to support lazy loading, and then go straight through the packaged code to see what lazy loading implementations look like. We need to have a basic directory configuration. The Demo directory structure is as follows:

Files/Directories instructions
src Import files, download modules, upload modules
index.html htmlTemplate file
webpack.config.js webpackThe configuration file
package.json Project description document

Function code implementation

Let’s have a look at our function code implementation, respectively download. Js, upload. Js, index.js.

// ./src/download.js
const download = () = > {
  console.log("download start");

  console.log("schedule download sdk");
  
  console.log("download");
}

export default download;
Copy the code
// ./src/upload.js
const upload = () = > {
  console.log("upload start");

  console.log("schedule upload sdk");
  
  console.log("upload");
}

export default upload;
Copy the code
// ./src/index.js
import download from "./download";

console.log("initial page");

async function handlerUploadClick() {
  // Dynamically load the upload module, whose default attribute is the upload method
  const { default: upload } = await import("./upload");
  // Call the upload method
  upload();
}

async function handlerDownloadClick() {
  download();
}

// Call the upload method when the Upload button is clicked
document.querySelector("#upload").addEventListener("click", handlerUploadClick, false)

// Call the download method when the Download button is clicked
document.querySelector("#download").addEventListener("click", handlerDownloadClick, false)
Copy the code
<! -- index.html -->
<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Webpack LazyLoad</title>
</head>

<body>
  <section>
    <h1>Home</h1>
    <button id="upload">Upload</button>
    <button id="download">Download</button>
  </section>
</body>

</html>
Copy the code

In our functional code implementation, we implemented an HTML web page, which has two buttons, one is upload button, one is download button.

Configuration to realize

Once the functionality is implemented, we need to configure The WebPack and then package it to produce a project that can run directly.

We create a new file webpack.config.js for configuration, and the code is as follows:

// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const WebpackChain = require("webpack-chain");

// Use webpack chain to assemble the configuration
const chain = new WebpackChain();

// Set the entry file to SRC /index.js
chain.entry("main").add("./src/index.js").end();

// Output the files generated by the build to the dist directory
chain.output.path(path.resolve(__dirname, "./dist")).end();

// Add html-webpack-plugin to set the HTML template file
chain.plugin("html-webpack-plugin").use(HtmlWebpackPlugin, [{
  template: path.resolve(__dirname, "./index.html")}]);// Set the source map generation rule
chain.devtool("cheap-source-map").end();

// Turn the configuration into a configuration object that webPack can recognize
const config = chain.toConfig();

module.exports = config;
Copy the code

As you can see from the code implementation, our WebPack configuration simply configures the entry, exit and HTML template files.

Next, we need to configure package.json and add the startup command to scripts as follows:

"scripts": {
  "build": "NODE_ENV=development webpack --config webpack.config.js && cd dist && anywhere"
}
Copy the code

Anywhere is a fast start HTTP service plug-in that can be installed globally using NPM I Anywhere -g.

After configuration, we need to run the following command to install some dependencies

npm i webpack webpack-cli webpack-chain html-webpack-plugin anywhere -D
Copy the code

With the dependencies installed, we are ready to start the project!

Run the project

We run NPM build to start the project compilation, and the command line output will look like this.

Our project was packaged by Webpack, exported to the dist directory, and ran a service from Anywhere on port 8000.

We open the browser and see the following page. (As shown below)

When we open the console, we see the corresponding output that we set up (as shown below).

Page operation

Let’s do some page actions. Click on the Download button and the console output will look like this.

As you can see from the figure above, the Download method is invoked and a mock operation is performed.

Now click the Upload button again and watch the console output (as shown below)

From the console you can see that our upload operation was called, but it seems to be the same as the download operation.

At this point, we need to switch to the Network control panel and view the network request. (As shown below)

As can be seen from the above figure, the file corresponding to the upload method will be loaded only when the upload method is called, thus realizing lazy loading.

The advantage of this is that it can effectively reduce the size of the main package on demand, speed up the first screen rendering, and reduce the bandwidth pressure on the server. It also reduces JS parsing time and improves page rendering speed.

Lazy loading implementation for the front end, performance optimization is a special required course. Arguably, the more complex the project, the greater the benefit of lazy loading.

Implementation analysis

Let’s take a look at the compiled webPack code to see how WebPack implements lazy loading.

First, we look at the main package file, dist/main.js. In this file, find the page initialization operations we implemented in SRC /index.js. (As shown below)

As you can see from the figure above, this operation is packaged directly into the bundle generated by the build.

The Download parsing

Let’s take a look at the download method call implemented in SRC /download.js.

As you can see from the figure above, handlerDownloadClick ends up calling the _download__webPack_imported_module_0__.default method.

And what is _download__webPack_imported_module_0__. default?

The assignment to this object is found in the built code (figure below)

The __webpack_require__ function loads the corresponding module in __webpack_modules__, which is the “./ SRC /download.js” module.

Finally, we found the definition of this module in dist/main.js. (As shown below)

As you can see from the figure above, the definition of this module, which is actually the SRC /download.js implementation, is packaged into dist/main.js as part of the __webpack_modules__ object.

The Upload parsing

Having looked at the package implementation of the Download method, let’s see how the lazy upload is implemented.

Let’s first find the function call corresponding to Upload (as shown below)

As you can see from the figure above, when the upload button is clicked, a load operation is performed using the __webpack_require__.e method. Let’s look at what this method does.

This method first concatenates the absolute path corresponding to the module (figure below)

The files in this path are actually the files generated in the dist directory after packaging (as shown below).

Then, the corresponding script file is inserted into the document by dynamically inserting script tags. (As shown below)

When the upload corresponding file is inserted, it will be executed automatically. The srC_upload_js.js script will execute the webpackJsonpCallback method, which will insert the lazy-loaded module into the Window’s webpackChunklazyload array. (As shown below)

After executing this function, the upload module is registered with __webpack_modules__, and the following call process is the same as calling Download.

summary

From a simple example, we learned about the lazy loading implementation of WebPack.

The lazy-loaded implementation of WebPack cuts the lazy-loaded code into separate packages when it is packaged, then loads it on demand in the main package, and then makes the call.

Let’s finish with a diagram to tease out lazy loading execution. (As shown below)

One last thing

If you’ve already seen it, please give it a thumbs up

Your likes are the greatest encouragement to the author, and can also let more people see this article!

If you find this article helpful, please help to light up the star on Github.