Lazy loading principle

Webpack lazy loading is actually a very simple concept: dynamic tag, can be understood as JSONP, principle is also dynamic insert script tag, Just this!!

Let’s first look at the implementation of JSONP

(function (window,document) { "use strict"; Var dataString = url.indexof('? ') var dataString = url.indexof('? ') = = 1? '? ':' & '; for(var key in data){ dataString += key + '=' + data[key] + '&'; }; Var cbFuncName = 'cb' + math.random ().toString().replace('.',''); dataString += 'callback=' + cbFuncName; // Create a script tag and insert it into the page var script = document.createElement('script'); script.src = url + dataString; Window [cbFuncName] = function (data) {callback(data); / / after processing the callback function data, delete the json document script tag. Body. RemoveChild (script). } / / append to the page of the document. The body. The appendChild (script). } window.jsonp = jsonp; })(window,document)Copy the code

Webpack lazily loads the implementation

  • Webpack import load source code
/** * @desc webpack is a function that dynamically loads scripts * @param chunkId packs automatically generated serial numbers for webpack, * import(/* webpackChunkName: 'Lazy' */'./Lazy') => Lazy.main.js */ __webpack_require__.e = function requireEnsure(chunkId) { var promises = []; InstalledChunkData = installedChunks[chunkId]; If (installedChunkData!) if(installedChunkData! == 0) {// 0 means "already installed". If (installedChunkData) {promises. Push (installedChunkData[2]); } else {// Wrap the dependency in a promise and push it into the cache, Var promise = new promise (function(resolve, reject) { installedChunkData = installedChunks[chunkId] = [resolve, reject]; }); ∨∨ promises: JsonCallback (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); } // ∨∨∨ site.src = jsonpScriptSrc(chunkId); // create error before stack unwound to get useful stacktrace later var error = new Error(); 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; 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(){onScriptComplete({type: 'timeout', target: script}); }, 120000); script.onerror = script.onload = onScriptComplete; / / in the document head inserted into the script tag. Head. The appendChild (script). } } return Promise.all(promises); };Copy the code

Compare the implementation of JSONP, is not found very similar, but also more step cache processing

  • WebpackJsonpCallback source
. // WebPack registers a webpackJsnop event under the window and overwrites the push event of this method, / / every lazy loading the push event triggered var jsonpArray window [" webpackJsonp "] = = window (" webpackJsonp ") | | []; var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); jsonpArray.push = webpackJsonpCallback; . = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = / / let's look at the import (/ * webpackChunkName: @file dist/lazy.main.js // file dist/lazy.main.js Window ["webpackJsonp"] // Push triggers the webpackJsonpCallback function, setting the dependency to 0, And perform then method (window [" webpackJsonp "] = window (" webpackJsonp ") | | []), push ([[" Lazy "] and {/ / comments ". / SRC/Lazy. Js ": (function(module, exports) { eval("var __signature__ = typeof reactHotLoaderGlobal ! == 'undefined' ? reactHotLoaderGlobal[\"default\"].signature : function (a) {\n return a;\n};\n\nconsole.log('This is a Lazy test');\n"); }),..., // if lazy.js has import dependencies, it will appear here}]); = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = / / then see webpackJsonpCallback method Function webpackJsonpCallback(data) {['Lazy'] var chunkIds = data[0]; / / load the dependent files in the file, the structure is roughly as follows / / {/ /. / SRC/Lazy. "" js" : (function () {}), / /. / SRC/XXX. "js" : (function () {}), / /... // } var moreModules = data[1]; var moduleId, chunkId, i = 0, resolves = []; for(; i < chunkIds.length; i++) { chunkId = chunkIds[i]; If (Object. The prototype. The hasOwnProperty. Call (installedChunks, chunkId) && installedChunks [chunkId]) {/ / here, Push (installedChunks[chunkId][0]); InstalledChunks [chunkId] = 0; installedChunks[chunkId] = 0; } // Iterate through the loop dependency, ∨∨ for(moduleId in moreModules) {function() {}) {// ∨ for(moduleId in moreModules) { if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; } } if(parentJsonpFunction) parentJsonpFunction(data); At this point, resolve in promises: at this point, __webpack_require__? }};Copy the code
  • __webpack_require__ source
// import(/* webpackChunkName: 'Lazy' * '. / Lazy "). Then (data = > console. The log (data)) / / in fact, __webpack_require__.e = function requirekid (chunkId) : import().then() is interpreted in webpack compilation as follows: Load the script __webpack_require__. E (/ *! Import () | Lazy * / \ "Lazy \"). Then (/ / webpackJsonpCallback final resolve. The shift () () will run to here __webpack_require__.bind(null,\"./src/Lazy.js\") ) .then( function (data) {\n console.log(data); \n } ); = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = / / there's a __webpack_require__ here, Function __webpack_require__(moduleId) {// Check whether global dependencies are already installed, Exports if(installedModules[moduleId]) {return installedModules[moduleId].exports; Var Module = installedModules[moduleId] = {I: moduleId, l: false, exports: {}, hot: hotCreateModule(moduleId), parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp), children: [], hot: hotCreateModule(moduleId), parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp), children: [] }; // In the webpackJsonpCallback callback, ∨∨ = (function(module, __webpack_exports__, __webpack_require__) {//... // console.log('xxx'); // }).call(module.exports, module, module.exports, __webpack_require__(moduleId)) modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId)); module.l = true; // imports ('./Lazy'). Then (data => console.log(data)) module.exports; }Copy the code

Webpack lazy load flow chart

Finally, the specific flow chart is attached

conclusion

This concludes the lazy loading implementation of WebPack. Doesn’t it feel so simple

Later, combined with the implementation principle of lazy loading, there may be a new sharing “Hot update implementation of their own hand lifting”.

(If anyone is watching)