Initial address: mp.weixin.qq.com/s/_rl5V6XX8…

Tagline: in order to better explain, the text code accounted for more words, do not worry ~

What you can learn from this article: WebPack’s support for modularity syntax, link execution of packaged modules, the process of dynamically loading modules, and a lot more that might be involved. Hint: some of them are in the notes, so look at them together.

Start of the text ~

At present, the front-end engineering through the construction of Webpack, support ESModule and CommonJs writing method, to meet the requirements of front-end modularization. This article will do an in-depth analysis of webpack module link and the implementation of dynamic acquisition module. And the knowledge points involved, such as treeShaking, CommonJs implementation, closure application are mentioned, so that we really know the implementation principle, want to eat fast food children can choose speed reading.

In the following example, we will use both ESModule and CommonJs syntax import and export to thoroughly analyze the work of WebPack. The code is as follows:

//index.js entry file import _, {name} from'./es';
let co = require('./common');
co.sayHello(name);
export default _;

//es.js
export const age = 18;
export const name = "Front Office";
export default "ESModule"; //common.js exports.sayHello = (name, desc) => {console.log(' welcome to [front end]~ '); }Copy the code

For a more complete presentation of webPack processing details, the webPack configuration used needs to be described below:

  • Since mode:production has scope promotion enabled by default, mode: development mode is used.

  • No compression plug-in is used.

  • Output.filename: ‘js/[name].[hash].js’ // Default name is main

After packaging code as follows (slightly longer, review comb use, first leave, scroll down! :

//main.9993bb.js
(function(modules) { // webpackBootstrap
   // The module cache
   var installedModules = {};
   // The require function
   function __webpack_require__(moduleId) {
     // Check if module is in cache
     if(installedModules[moduleId]) {
       return installedModules[moduleId].exports;
     }
     // Create a new module (and put it into the cache)
     var module = installedModules[moduleId] = {
       i: moduleId,
       l: false,
       exports: {}
     };
     // Execute the module function
     modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
     // Flag the module as loaded
     module.l = true;
     // Return the exports of the module
     return module.exports;
   }
   // expose the modules object (__webpack_modules__)
   __webpack_require__.m = modules;
   // expose the module cache
   __webpack_require__.c = installedModules;
   // define getter function for harmony exports
   __webpack_require__.d = function(exports, name, getter) {
     if(! __webpack_require__.o(exports, name)) { Object.defineProperty(exports, name, { enumerable:true, get: getter }); }}; // define __esModule on exports __webpack_require__.r =function(exports) {
     if(typeof Symbol ! = ='undefined' && Symbol.toStringTag) {
       Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
     }
     Object.defineProperty(exports, '__esModule', { value: true });
   };
   // create a fake namespace object
   // mode & 1: value is a module id, require it
   // mode & 2: merge all properties of value into the ns
   // mode & 4: return value when already ns object
   // mode & 8|1: behave like require
   __webpack_require__.t = function(value, mode) {
     if(mode & 1) value = __webpack_require__(value);
     if(mode & 8) return value;
     if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
     var ns = Object.create(null);
     __webpack_require__.r(ns);
     Object.defineProperty(ns, 'default', { enumerable: true, value: value });
     if(mode & 2 && typeof value ! ='string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
     return ns;
   };
   // getDefaultExport function for compatibility with non-harmony modules
   __webpack_require__.n = function(module) {
     var getter = module && module.__esModule ?
       function getDefault() { return module['default']; } :
       function getModuleExports() { return module; };
     __webpack_require__.d(getter, 'a', getter);
     return getter;
   };
   // Object.prototype.hasOwnProperty.call
   __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
   // __webpack_public_path__
   __webpack_require__.p = "/";
   // Load entry module and return exports
   return__webpack_require__(__webpack_require__.s = 0); ({})"./src/index.js": / *! exports provided: default */ /*! all exports used */ (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    /* harmony import */ 
    var _es__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./es */ "./src/es.js");
    var co = __webpack_require__(/*! ./common */ "./src/common.js"); // import co from './common';
    co.sayHello(_es__WEBPACK_IMPORTED_MODULE_0__[/* name */ "b"]);
    /* harmony default export */ 
    __webpack_exports__["default"] = (_es__WEBPACK_IMPORTED_MODULE_0__[/* default */ "a"]);
  }),
  "./src/es.js": / *! exports provided: age, name, default */ /*! exports used: default, name */ (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    /* unused harmony export age */
    /* harmony export (binding) */ 
    __webpack_require__.d(__webpack_exports__, "b".function() { return name; });
    var age = 18;
    var name = "Front Office";
    /* harmony default export */ 
    __webpack_exports__["a"] = ("ESModule");
  }),
  "./src/common.js": / *! no static exports found */ /*! all exports used */ (function(module, exports) {
    exports.sayHello = function (name, desc) {
      console.log("\u6B22\u8FCE\u5173\u6CE8[\u524D\u7AEF\u4E8B\u52A1\u6240]~");
    };
  }),
  0:
  (function(module, exports, __webpack_require__) { module.exports = __webpack_require__(/*! * /"./src/index.js"); })}); //# sourceMappingURL=main.6196cc781843c8696cda.js.map
Copy the code

It seems a bit long, and many of you might be told to leave, so here’s the short version:

 (function(modules) { // webpackBootstrap
   //...
   // Load entry module and return exports
   return__webpack_require__(__webpack_require__.s = 36); ({})"./src/index.js": 
  (function(module, __webpack_exports__ __webpack_require__) {/ * * / module content}),"./src/es.js": 
  (function(module, __webpack_exports__ __webpack_require__) {/ * * / module content}),"./src/common.js": 
  (function(Module, exports) {/* Module contents */})}); //# sourceMappingURL=main.6196cc781843c8696cda.js.map
Copy the code

This is much better. We can get the following information roughly from the above:

1) Our modules are converted into immediate function expressions (IIFE). Functions are self-executing, creating modules, linking, etc. (Runtime code)

2) All modules are assembled into objects passed in as arguments to functions. Object composition: {[file path] : [wrapped module contents]};

3) Each module is wrapped in a constructed function. (Module code conversion)

Let’s disassemble the above code and analyze in detail how modules are encapsulated and linked together.

Module code conversion

Since WebPack supports not only ESM’s import and export syntax, but also CommonJs’s require and exports syntax, we’ll examine them separately.

Let’s first look at how the “ESM specification “code is handled:

"./src/es.js": / *! exports provided: age, name, default */ /*! exports used: default, name */ (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    /* unused harmony export age */
    /* harmony export (binding) */ 
    __webpack_require__.d(__webpack_exports__, "b".function() { return name; });
    var age = 18;
    var name = "Front Office";
    /* harmony default export */ 
    __webpack_exports__["a"] = ("ESModule");
  })
Copy the code

Analysis from top to bottom:

1) There are some comments on each function:

// Exports provided // exports usedCopy the code

The function body also has a similar comment inside:

// Unused export unused harmonyexportAge // Used export, (type: Use type) harmonyexport (binding)
Copy the code

It is based on the recording of interface information that Webapck can implement treeShaking. For details, see the Tree Shaking principle.

2) Function parameters are: module, __webpack_exports__, __webpack_require__

It is important to note that CommonJs exports module objects, ESM specifications do not have module objects, so you can use this===undefined to determine whether the current environment is in a module. But WebPack supports ESM syntax by converting it to a load form similar to CommonJs, except that modules are read from memory rather than from hard disk via file stream (see the modularity introduction for a simple implementation of CommonJs).

__webpack_exports__ === Module. exports === CommonJs; CommonJs supports both module. Exports and exports, the same implementation.

Webpack replaces the import keyword with __webpack_require__.

Age and name are converted to variable declarations.

You can see that there is a __webpack_require__.d method and see what it does (see the comment) :

// define getter function for harmony exports
__webpack_require__.d = function(exports, name, getter) {// Check whether the variable is already mounted on exportsif(! __webpack_require__.o(exports, name)) {// Add an export variable (interface) to exports, Object. DefineProperty (exports, name, {enumerable: exports, name, {enumerable: exports, name, {enumerable:true, get: getter }); }};Copy the code

The exported variable is bound to exports. Age is not registered with exports because it is marked unused. While binding name to exports with __webpack_require__.d, there are three points to note:

  • The method of passing a reference through a closure (an implementation of the getter) is intended to implement the ESM specification: an export is not a copy of a value, but a shared reference. When exports.name is used, the getter is triggered to return its current value;

  • Add an explicit property descriptor {enumerable: true, get: getter} for an object property, because set: undefined, it cannot be changed in strict mode (“use strict”).

  • Careful children will notice that __webpack_require__.d is executed first by putting it at the top of the module. Why? In order to realize the ESM export promotion (the difference between variable | function, see modular ES in circular dependencies), pay attention to the module initialization time and introduced later in the cache with understanding.

__webpack_exports__[“a”] = (“ESModule”); The a is default and is also mounted on module.exports. The difference with the name interface export definition is that default can be reassigned, for example:

import * as ES from './a.js'
ES.name = 1; //Uncaught TypeError: Cannot set property name of #<Object> which has only a getter
ES.default = 123; //ok
Copy the code

This is the key part of the ESM export, which basically covers common processing scenarios and is not all that mysterious

So far, the export section of ESM is generally covered. Let’s take a look at how Webpack handles CommonJs export as follows:

"./src/common.js": / *! no static exports found */ /*! all exports used */ (function(module, exports) {
  exports.sayHello = function (name, desc) {
    console.log("\u6B22\u8FCE\u5173\u6CE8[\u524D\u7AEF\u4E8B\u52A1\u6240]~");
  };
})
Copy the code

As you can see, the module code is basically unchanged. It is also encapsulated in functions and passed in module objects, mimicking the CommonJs implementation. No further elaboration.

Finally, take a look at how the index.js entry file imports the module:

"./src/index.js":
(function(module, __webpack_exports__, __webpack_require__) {
  "use strict";
  __webpack_require__.r(__webpack_exports__);
  /* harmony import */ 
  var _es__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./es */ "./src/es.js");
  var co = __webpack_require__(/*! ./common */ "./src/common.js");
  co.sayHello(_es__WEBPACK_IMPORTED_MODULE_0__[/* name */ "b"]);
  /* harmony default export */ 
  __webpack_exports__["default"] = (_es__WEBPACK_IMPORTED_MODULE_0__[/* default */ "a"]);
})
Copy the code

__webpack_require__ returns a module object. What is __webpack_require__.r?

// define __esModule on exports
__webpack_require__.r = function(exports) {
 if(typeof Symbol ! = ='undefined' && Symbol.toStringTag) {
   Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
 }
 Object.defineProperty(exports, '__esModule', { value: true });
};
Copy the code

The main function is to mark the currently packaged module, indicating that it is exported in accordance with the ESM specification; In general, when the default export is obtained by import, the code packaged by Webpack uses the flag __esModule to determine whether it is an ESM export, and then returns the appropriate value as the default interface value.

Let co = require(‘./common.js’); You can also use import co from ‘./common.js’; After the package CommonJs module import conversion code into the following form:

var _common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./common */ "./src/common.js");
Copy the code

Let’s take a look at what __webpack_require__.n does with the acquired module:

// getDefaultExport function for compatibility with non-harmony modules
__webpack_require__.n = function(module) {
 var getter = module && module.__esModule ?
   function getDefault() { return module['default']; } :
   function getModuleExports() { return module; };
 __webpack_require__.d(getter, 'a', getter);
 return getter;
};
Copy the code

As you can see, __webpack_require__.n mainly gets the default export of the module. If the module is __esModule, return module[‘default’] or module object if it is not. Because in the CommonJs specification, the default export of a module is the Module object itself. Module is the __webpack_require__.n(module) argument, the module.exports object, not to be confused).

So why doesn’t __webpack_require__.n get the default _ in es.js? In _webpack_require__.n, the default value is actually returned by the reader of the a property; Export default directly uses A to bind exports, and also uses A to fetch exports. Because it is an internal ESM, WebPack is built with the knowledge of how modules are exported, so the intermediate steps are omitted.

This completes the conversion of the module code, so how does the module perform in the browser? The next step is to analyze how the modules are linked together.

Link to module code (Runtime)

Once packaged, a webpack launcher is loaded by the browser along with the module information, controlling the creation and execution of the module. Now that we have covered the parameters section of IIFE, here is the function body (startup code) :

(function(modules) {// webpackBootstrap // module cache, singleton mode var installedModules = {}; // import and require are replaced with __webpack_require__ for creating and loading modulesfunction__webpack_require__(moduleId) {// Return the module object directly when the module has been cachedif(installedModules[moduleId]) {
       returninstalledModules[moduleId].exports; } / / create a new object | m module into the cache 【 note 】 when circular dependencies var module = installedModules/moduleId = {I: moduleId, l:falseExports: {}}; // Exports: {}}; // pass module, module.exports, __webpack_require__ to the wrapped function, Modules [moduleId]. Call (module.exports, module, module.exports, __webpack_require__); // Flag the module as loaded module.l =true;
     // Return the exports of the module
     returnmodule.exports; } / * *... * Some helper functions mounted on __webpack_require__. D * __webpack_require__. R * */ */ */ */ */ */ */ */ */function(module, exports, __webpack_require__) { // module.exports = __webpack_require__(/*! * /"./src/index.js");
   // })
   return __webpack_require__(__webpack_require__.s = 0);
 })
Copy the code

This section recommends reading the code in conjunction with comments. Well, the general module conversion and runtime functions have been covered

That’s it? Support for import() dynamic loading for Webpack. How does this work?

import()

The following is an example:

//index.js import file import(/* webpackChunkName:"es"* /'./es.js')
  .then((val => console.log(val)))

//es.js
export const name = "Front Office";
export default "ESModule";
Copy the code

Es.js is the module that needs to be loaded with import(), and the code is as follows:

/ / webpackJsonp: [['Module name (Id)', {'Module path'}]] (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["es"] and {"./src/es.js":
  (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    __webpack_require__.d(__webpack_exports__, "name".function() { return name; });
    var name = "Front Office";
    __webpack_exports__["default"] = ("ESModule"); }}));Copy the code

We know that the objects of the entry module are packaged as parameters of the Runtime function, while asynchronously acquired modules are wrapped in the same form, pushed into the webpackJsonp array or executed immediately (webpackJsonp. Push is a push on the prototype chain or a callback function again, It is determined by the order in which the asynchronous module and runtime are executed, which comes later. In addition, the module code has been described in detail above, and will not be described here.

Let’s look at some of the runtime code in main.js (only a few key bits are listed here) :

(function(modules) {**** key code 3: asynchronous module callback function **** // install a JSONP callbackfor chunk loading
  functionwebpackJsonpCallback(data) {
   var chunkIds = data[0];
   var moreModules = data[1];
  
  
   // add "moreModules" to the modules object,
   // then flag all "chunkIds" as loaded and fire callback
   var moduleId, chunkId, i = 0, resolves = [];
   for(; i < chunkIds.length; i++) { chunkId = chunkIds[i];if(installedChunks[chunkId]) {
       resolves.push(installedChunks[chunkId][0]);
     }
     installedChunks[chunkId] = 0;
   }
   for(moduleId in moreModules) {
     if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; }}if(parentJsonpFunction) parentJsonpFunction(data);
  
   while(resolves.length) { resolves.shift()(); }}; **** __webpack_require__.e = functionrequireEnsure(chunkId) {var promises = []; // JSONP chunk loadingfor javascript
   var installedChunkData = installedChunks[chunkId];
   if(installedChunkData ! == 0) { // 0 means"already installed".
  
     // a Promise means "currently loading".
     if(installedChunkData) {
       promises.push(installedChunkData[2]);
     } else {
       // setup Promise in chunk cache
       var promise = new Promise(function(resolve, reject) {
         installedChunkData = installedChunks[chunkId] = [resolve, reject];
       });
       promises.push(installedChunkData[2] = promise);
  
       // start chunk loading
       var script = document.createElement('script');
       var onScriptComplete;
  
       script.charset = 'utf-8';
       script.timeout = 120;
       if (__webpack_require__.nc) {
         script.setAttribute("nonce", __webpack_require__.nc);
       }
       script.src = jsonpScriptSrc(chunkId);
  
       onScriptComplete = function (event) {
         // avoid mem leaks in IE.
         script.onerror = script.onload = null;
         clearTimeout(timeout);
         var chunk = installedChunks[chunkId];
         if(chunk ! = = 0) {if(chunk) {
             var errorType = event && (event.type === 'load' ? 'missing' : event.type);
             var realSrc = event && event.target && event.target.src;
             var error = new Error('Loading chunk ' + chunkId + ' failed.\n(' + errorType + ':' + realSrc + ') '); error.type = errorType; error.request = realSrc; chunk[1](error); } installedChunks[chunkId] = undefined; }}; var timeout =setTimeout(function(){
         onScriptComplete({ type: 'timeout', target: script }); }, 120000); script.onerror = script.onload = onScriptComplete; document.head.appendChild(script); }}returnPromise.all(promises); }; 2: * * * * key code registration | registered module of the callback function execution window [* * * * varjsonpArray ="webpackJsonp"] = window["webpackJsonp"] | | []; varoldJsonpFunction = jsonpArray.push.bind(jsonpArray); jsonpArray.push = webpackJsonpCallback; jsonpArray = jsonpArray.slice();for(vari = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
  varparentJsonpFunction = oldJsonpFunction;

  // Load entry module and return exports
  return__webpack_require__(__webpack_require__.s = 0); ({})"./src/index.js":
  (function(module, __webpack_exports__ __webpack_require__) {* * * * key code 4: import () the transformation of the * * * * __webpack_require__. E (/ *! import() | es */"es").then(__webpack_require__.bind(null, /*! ./es.js */ "./src/es.js")).then(function (val) {
      returnconsole.log(val); }); }}); })Copy the code

Here are the four key pieces of code, in order:

Import () is converted to __webpack_require__.e(/*! Import () | es * / “es”), to see the first __webpack_require__. E code:

// JSONP chunk loading forjavascript __webpack_require__.e = functionrequireEnsure(chunkId) { var promises = []; var installedChunkData = installedChunks[chunkId]; // Check whether the current module has been loaded (after loading, it will be marked as 0)if(installedChunkData ! == 0) {// If the request is not undefined, it means that this module has been sent, loging stateif(installedChunkData) {// If the module is loading, store promises recorded in the module cache into Promises Promises. Push (installedChunkData[2]); }else{// Create a new Promise, Use installedChunks to record the resolve and reject chunks that the module will return to a Promise.function(resolve, reject) { installedChunkData = installedChunks[chunkId] = [resolve, reject]; }); //installedChunkData[chunkId]: [resolve, reject, promise] promises.push(installedChunkData[2] = promise); Var script = document.createElement('script');
     var onScriptComplete;

     script.charset = 'utf-8';
     script.timeout = 120;
     if (__webpack_require__.nc) {
       script.setAttribute("nonce", __webpack_require__.nc);
     }
     script.src = jsonpScriptSrc(chunkId);

     onScriptComplete = function (event) {
       // avoid mem leaks in IE.
       script.onerror = script.onload = null;
       clearTimeout(timeout);
       var chunk = installedChunks[chunkId];
       if(chunk ! = = 0) {if(chunk) { //... } installedChunks[chunkId] = undefined; }}; // Processing asynchronous module loading timeout var timeout =setTimeout(function(){
       onScriptComplete({ type: 'timeout', target: script }); }, 120000); / / modules loaded (failure) | success do processing: removing the timer etc script. The onerror = script. The onload = onScriptComplete; document.head.appendChild(script); }} //import () returns a Promise instance, promises record cached promises when the module is loaded Will inform to all request the import of the module () callback execution / / equivalent to the module for slow amount is promise to register multiple callback function: execute sequentially: / / p.t hen (A dynamic loading request callback) | p.t hen dynamic load request callback (B)return Promise.all(promises);
};
Copy the code

A brief introduction (the notes in the article have been explained more clearly) :

1) Create a Promise object and use installedChunks to record its resolve and reject so as to switch the context and control the execution timing of.then() after obtaining resources;

2) installedChunks are used to record chunks that have been loaded and are being loaded;

// installedChunks: undefined = chunk is not loaded yet; Null = prefecth/preload; Promise = chunk loading; 0 = Chunk loading is complete.Copy the code

3) Then create a Script tag and initiate an asynchronous request (requireJs is also asynchronously loaded in a similar way)

If the module is loaded before runtimeChunk, it will be stuffed into the window[“webpackJsonp”] and wait for the webapck callback to execute. If executed later than runtimeChunk, window[“webpackJsonp”]. Push is the webpackJsonpCallback and is executed immediately. Let’s start with the following code:

var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] | | []; var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); jsonpArray.push = webpackJsonpCallback; jsonpArray = jsonpArray.slice();for(vari = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
var parentJsonpFunction = oldJsonpFunction;
Copy the code

1) Check whether window[“webpackJsonp”] has been created;

Here to explain, for example by configuration optimization. RuntimeChunk: If the runtime runtime code is packaged separately, the runtime and main.js js files will be generated, and both files will be inserted into the index.html script. So you have to think about that.

Review the flow control solutions: function nesting, Promise, Generator. The solution used above is similar to the implementation of thunk control automatic execution:

function thunkFun() {
  letval; // Simulate asynchronous operationssetTimeout(() => {
    let msg = 'Front Office';
    if(val) {
      val(msg); return; } val = msg; }, 1000).return (callback) => {
    if(! val) { val = callback;return; } callback(val); }} // uselet run = new thunkFun();
letcallback = val => console.log(val); // Run (callback); // Run (callback); // Case 2: The simulated asynchronous operation completes before the callback function is registeredsetTimeout(() => {
  run(callback)
}, 3000);
Copy the code

It is this switch in automatic execution that makes it, like Promise, a self-executor of the Generator. See Flow Control for details. Redux-thunk should be known if you’ve used React. Also note the distinction between thunk (which emphasizes passing in callback functions) and Curryification.

2) If the asynchronous module is loaded first, it will be cached in the webpackJsonp array and wait for the execution of calling webpackJsonpCallback;

3) If the Runtime code is loaded first, the webPackJsonp. push will be overridden and executed after the asynchronous module is loaded, which is equivalent to calling the webpackJsonpCallback directly.

Let’s look directly at what the webpackJsonpCallback asynchronous callback does to the module:

functionwebpackJsonpCallback(data) { var chunkIds = data[0]; Var moreModules = data[1]; // moduleName (id) var moreModules = data[1]; Var moduleId, chunkId, I = 0, convergency = [];for(; i < chunkIds.length; i++) { chunkId = chunkIds[i];if(installedChunks[chunkId]) {// Collect the resolve chunks recorded in installedChunks of the asynchronous module.  //[resolve, reject, promise] resolves.push(installedChunks[chunkId][0]); InstalledChunks [chunkId] = 0; } // Register with global modules:[] (all modules are collected centrally in modules)for(moduleId in moreModules) {
   if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; }} // Push method on the prototype chain of the webpackJsonp arrayif(parentJsonpFunction) parentJsonpFunction(data);

 while// Import ().then() equivalent to promise.all (promises).then().shift()(); }};Copy the code

A brief introduction (with comments to see the code) :

1) Mark asynchronously loaded modules as complete: installedChunks[chunkId] = 0; (Don’t forget to set setTimeout and onScriptComplete to timeout and catch exceptions when creating script asynchronous fetch modules.)

2) Cache asynchronously loaded modules in globally maintained modules (the module content is not executed immediately after downloading), and the actual execution is responsible when calling __webpack_require__;

3) Because installedChunks record the corresponding [resolve, Reject, promise] of the module, resolve is called after loading to trigger the callback function.

Now, the asynchronous module information is logged and resolve executes the __webpack_require__.e callback via installedChunks:

__webpack_require__.e(/*! import() | es */ "es")
  .then(__webpack_require__.bind(null, /*! ./es.js */ "./src/es.js"))
  .then(function (val) {
    return console.log(val);
  });
Copy the code

As mentioned earlier, asynchronous modules are stored in modules when they are downloaded. You can see that __webpack_require__. E returns the promise’s callback function, __webpack_require__, which finds the module through modules and then executes and returns modules.exports.

Now we know that asynchronous modules cache the module in modules after downloading and trigger the promise callback. The actual creation and retrieval of the module object is done in the __webpack_require__ callback function. Instead of just fetching the module object and passing it in by calling the resolve(module.exports) callback to promise.

This completes the import() dynamically loaded process.

conclusion

RuntimeChunk is a runtimeChunk, runtimeChunk, runtimeChunk, runtimeChunk, runtimeChunk, runtimeChunk, runtimeChunk, runtimeChunk, runtimeChunk

This paper basically covers webpack module conversion, module link during execution, and module dynamic loading processing. In the process of telling, related knowledge points are explained as far as possible, which helps readers to consolidate what they have learned and apply what they have learned.

If you have read from the beginning to this point, it is recommended that you have a general impression of the content of this article, and then comb through the whole code, hoping to help you. If you have any questions, please communicate with us

Related to recommend

Tree Shaking Principle – webpack series

ES6 intensive Reading 【 Key Series 】

(1) (Control process related)