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 } */ 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?