How to implement modular loading of Web pack

The module specifications supported by webpack are AMD ,CommonJS,ES2015 import  Such norms. No matter what kind of specification, it can be roughly divided into synchronous loading and asynchronous loading. This article will show you how webback implements module management and loading.

Load synchronously as follows:

import a from './a';
console.log(a);

Asynchronous loading is as follows:

import('./a').then(a => console.log(a));

The startup function implemented by webacks directly passes the entry program module into the startup function and exists in the closure, as follows:

(function(modules){
......
//Load the entry module and export (implement the startup program)
return __webpack_require__(__webpack_require__.s = 0);
})({
0: (function(module, __webpack_exports__, __webpack_require__) {
module.exports = __webpack_require__(/*! ./src/app.js */"./src/app.js");
})
})

In terms of module management, whether the server or the client is the same, installedChunks records the loaded chunks and installedModules records the executed modules, as follows:

/**
* module Buffer
* key Is moduleId (usually the file path)
* value For module object {i: moduleId, {l: false, {exports: {}}
*/
var installedModules = {};
/**
* chunks Load status recorder
* key Generally, it is a chunk index
* value undefined:Not loaded 0: loaded (client specific null: ready to load [resolve, reject]: loading)
*/
var installedChunks = {
"app": 0
}

The method of synchronous loading is the same for both the server and the client. It is mainly to check whether there are modules to be loaded in the installedModules. If there are modules to be loaded, they will be returned directly. Otherwise, a new module will be created and module.exports will be returned. The specific implementation is as follows:

//Synchronous loading after compilation
__webpack_require__(/*! ./src/app.js */"./src/app.js");

//The method to load the module, i.e. the require method
function __webpack_require__(moduleId) {
//Check whether the current module already exists in the cache
if(installedModules[moduleId]) {
return installedModules[moduleId].exports; //Directly return cached module.exports
}
//Create a new module and add it to the cache
var module = installedModules[moduleId] = {
i: moduleId,
l: false, //Is it loaded
exports: {} //Exposed objects
};
//Method to execute the current module
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
//Mark module loading completion status
module.l = true;
//Return the exposed exports object of module
return module.exports;
}

The asynchronous loading of the server is to load the chunk through the node's require method and return a promises object. All chunks expose ids and modules objects. The specific implementation is as follows:

//Asynchronous loading method after compilation
__webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./c.js */ "./src/c.js"))

//The code of chunk 0 is as follows (that is, the code of 0.js)
exports.ids = [0];
exports.modules = {
"./src/c.js": (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_exports__["default"] = (function () {
console.log('c');
})
})
}

//Asynchronous module loading method
__webpack_require__.e = function requireEnsure(chunkId) {
var promises = [];
if(installedChunks[chunkId] !== 0) {
var chunk = require("./" + ({}[chunkId]||chunkId) + ".js");
var moreModules = chunk.modules, chunkIds = chunk.ids;
for(var moduleId in moreModules) {
modules[moduleId] = moreModules[moduleId];
}
for(var i = 0; i < chunkIds.length; i++)
installedChunks[chunkIds[i]] = 0;
}
return Promise.all(promises);
}

The asynchronous loading of client is to load resources through JSONP principle, save chunk contents ([chunkIds, modules]) into the global webbackjsonp array, and modify the push method of webbackjsonp to monitor chunk loading completion events. The specific implementation is as follows:

//Asynchronous loading method after compilation
__webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./c.js */ "./src/c.js"))

//The code of chunk 0 is as follows (that is, the code of 0.js)
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{
"./src/c.js": (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_exports__["default"] = (function () {
console.log('c');
});
})
}]);

//Load successful callback function
function webpackJsonpCallback(data) {
var chunkIds = data[0];
var moreModules = data[1];

//Mark the chunk returned from this load as the loading completion state and execute the callback
var moduleId, chunkId, i = 0, resolves = [];
for(;i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0]); //Add the chunk success callback to the queue to be executed
}
installedChunks[chunkId] = 0; //Mark chunk as load complete
}
//Add the module loaded this time to the global modules object
for(moduleId in moreModules) {
if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules[moduleId] = moreModules[moduleId];
}
}
//Judge whether the original push method of the webbackjsonp array exists, and append the data to the webbackjsonp if it exists
if(parentJsonpFunction) parentJsonpFunction(data);
//Execute all chunk callbacks
while(resolves.length) {
resolves.shift()();
}
};

//Implementation of load complete monitoring method
var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
jsonpArray.push = webpackJsonpCallback;
jsonpArray = jsonpArray.slice();
for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
var parentJsonpFunction = oldJsonpFunction;

//Asynchronous module loading method
__webpack_require__.e = function requireEnsure(chunkId) {
var promises = [];
var installedChunkData = installedChunks[chunkId];
if(installedChunkData !== 0) { //0 indicates that the installation is complete
if(installedChunkData) { //Loading
promises.push(installedChunkData[2]);
} else {
//Create a callback Promise and cache the Promise into installedChunks
var promise = new Promise(function(resolve, reject) {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
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);

var error = new Error();
onScriptComplete = function (event) { //Load complete callback
//? avoid IE memory leaks.
script.onerror = script.onload = null;
clearTimeout(timeout); //Turn off the timeout timer
var chunk = installedChunks[chunkId];
if(chunk !== 0) { //Load not completed
if(chunk) { //Loading
var errorType = event && (event.type === 'load' ? 'missing' : event.type);
var realSrc = event && event.target && event.target.src;
error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
error.name = 'ChunkLoadError';
error.type = errorType;
error.request = realSrc;
chunk[1](error);
}
installedChunks[chunkId] = undefined;
}
};
var timeout = setTimeout(function(){ //Set timeout timer
onScriptComplete({ type: 'timeout', target: script });
}, 120000);
script.onerror = script.onload = onScriptComplete; //Set load complete callback
document.head.appendChild(script);
}
}
return Promise.all(promises);
};


Article Sync: https://www.geek-share.com/detail/2784034803.html

Reference article:

How to implement lazy loading in webpack + react + react router

How can webpack2 + vue2 + Vue router2 achieve lazy loading?

 


Tags: Javascript Webpack React IE Vue

Posted on Wed, 06 Nov 2019 13:14:17 -0500 by tazz