Webpack 运行时代码分析 - 动态加载

news2024/11/19 13:25:25

文章内容:用 webpack 打包含有动态加载的模块,分析打包后的代码,也就是 webpack 运行时代码。

先思考如下一些问题:

1.什么叫做动态加载
2.如果不使用 webpack 打包,能做到动态加载吗
3.webpack 是如何实现动态加载的
4.webpack 处理动态加载与静态 import 的区别是什么

代码准备

index.js

import test from './test';

console.log("test", test);

const loadSum = () => {import('./sum').then(module => {console.log(module.default(6, 9))})
}

const btn = document.getElementById("btn");
btn.addEventListener("click", loadSum, false); 

test.js

export default 'test'; 

sum.js

const sum = (a, b) => {return a + b;
}

export default sum; 

webpack.config.js

const path = require('path')
module.exports = {
  entry: './index.js',
  output: {
    path: path.resolve(__dirname, 'build')
  },
  mode: 'none',
} 

在控制台执行

npx webpack 

输出 build/main.js 和 build/1.js

build/main.js

/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	var __webpack_modules__ = ([
/* 0 */,
/* 1 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ('test');

/***/ })
/******/ 	]);
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = __webpack_modules__;
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/ensure chunk */
/******/ 	(() => {
/******/ 		__webpack_require__.f = {};
/******/ 		// This file contains only the entry chunk.
/******/ 		// The chunk loading function for additional chunks
/******/ 		__webpack_require__.e = (chunkId) => {
/******/ 			return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
/******/ 				__webpack_require__.f[key](chunkId, promises);
/******/ 				return promises;
/******/ 			}, []));
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/get javascript chunk filename */
/******/ 	(() => {
/******/ 		// This function allow to reference async chunks
/******/ 		__webpack_require__.u = (chunkId) => {
/******/ 			// return url for filenames based on template
/******/ 			return "" + chunkId + ".js";
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/global */
/******/ 	(() => {
/******/ 		__webpack_require__.g = (function() {
/******/ 			if (typeof globalThis === 'object') return globalThis;
/******/ 			try {
/******/ 				return this || new Function('return this')();
/******/ 			} catch (e) {
/******/ 				if (typeof window === 'object') return window;
/******/ 			}
/******/ 		})();
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/load script */
/******/ 	(() => {
/******/ 		var inProgress = {};
/******/ 		// data-webpack is not used as build has no uniqueName
/******/ 		// loadScript function to load a script via script tag
/******/ 		__webpack_require__.l = (url, done, key, chunkId) => {
/******/ 			if(inProgress[url]) { inProgress[url].push(done); return; }
/******/ 			var script, needAttach;
/******/ 			if(key !== undefined) {
/******/ 				var scripts = document.getElementsByTagName("script");
/******/ 				for(var i = 0; i < scripts.length; i++) {
/******/ 					var s = scripts[i];
/******/ 					if(s.getAttribute("src") == url) { script = s; break; }
/******/ 				}
/******/ 			}
/******/ 			if(!script) {
/******/ 				needAttach = true;
/******/ 				script = document.createElement('script');
/******/ 		
/******/ 				script.charset = 'utf-8';
/******/ 				script.timeout = 120;
/******/ 				if (__webpack_require__.nc) {
/******/ 					script.setAttribute("nonce", __webpack_require__.nc);
/******/ 				}
/******/ 		
/******/ 				script.src = url;
/******/ 			}
/******/ 			inProgress[url] = [done];
/******/ 			var onScriptComplete = (prev, event) => {
/******/ 				// avoid mem leaks in IE.
/******/ 				script.onerror = script.onload = null;
/******/ 				clearTimeout(timeout);
/******/ 				var doneFns = inProgress[url];
/******/ 				delete inProgress[url];
/******/ 				script.parentNode && script.parentNode.removeChild(script);
/******/ 				doneFns && doneFns.forEach((fn) => (fn(event)));
/******/ 				if(prev) return prev(event);
/******/ 			};
/******/ 			var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
/******/ 			script.onerror = onScriptComplete.bind(null, script.onerror);
/******/ 			script.onload = onScriptComplete.bind(null, script.onload);
/******/ 			needAttach && document.head.appendChild(script);
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/make namespace object */
/******/ 	(() => {
/******/ 		// define __esModule on exports
/******/ 		__webpack_require__.r = (exports) => {
/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 			}
/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/publicPath */
/******/ 	(() => {
/******/ 		var scriptUrl;
/******/ 		if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + "";
/******/ 		var document = __webpack_require__.g.document;
/******/ 		if (!scriptUrl && document) {
/******/ 			if (document.currentScript)
/******/ 				scriptUrl = document.currentScript.src
/******/ 			if (!scriptUrl) {
/******/ 				var scripts = document.getElementsByTagName("script");
/******/ 				if(scripts.length) scriptUrl = scripts[scripts.length - 1].src
/******/ 			}
/******/ 		}
/******/ 		// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
/******/ 		// or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
/******/ 		if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
/******/ 		scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/?.*$/, "").replace(//[^/]+$/, "/");
/******/ 		__webpack_require__.p = scriptUrl;
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/jsonp chunk loading */
/******/ 	(() => {
/******/ 		// no baseURI
/******/ 		
/******/ 		// object to store loaded and loading chunks
/******/ 		// undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ 		// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded// installedChunks 存放 已经加载了 和 正在加载 的 chunks// 有几种取值// 0-> 已经加载了的 chunk// [resolve, reject, Promise] -> 正在加载的 chunk// undefined-> chunk 没有加载// null -> chunk preloaded/prefetched
/******/ 		var installedChunks = {
/******/ 			0: 0
/******/ 		};
/******/ 		
/******/ 		__webpack_require__.f.j = (chunkId, promises) => {
/******/ 				// JSONP chunk loading for javascript
/******/ 				var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
/******/ 				if(installedChunkData !== 0) { // 0 means "already installed".
/******/ 		
/******/ 					// a Promise means "currently loading".
/******/ 					if(installedChunkData) {
/******/ 						promises.push(installedChunkData[2]);
/******/ 					} else {
/******/ 						if(true) { // all chunks have JS
/******/ 							// setup Promise in chunk cache// installedChunkData 先赋值为 [resolve, reject]// 注意这里的 resolve,有用,后面在成功加载到 1.js 后就是执行这个 resolve(),改变了 promise 的状态
/******/ 							var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));// installedChunkData -> [resolve, reject, Promise]// 这个时候 promise 实例的状态为 pending
/******/ 							promises.push(installedChunkData[2] = promise);
/******/ 		
/******/ 							// start chunk loading// 得到需要加载chunk 的 url
/******/ 							var url = __webpack_require__.p + __webpack_require__.u(chunkId);
/******/ 							// create error before stack unwound to get useful stacktrace later// 进行错误处理 -> 未成功加载到某个 chunk
/******/ 							var error = new Error();
/******/ 							var loadingEnded = (event) => {
/******/ 								if(__webpack_require__.o(installedChunks, chunkId)) {
/******/ 									installedChunkData = installedChunks[chunkId];
/******/ 									if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
/******/ 									if(installedChunkData) {
/******/ 										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;
/******/ 										installedChunkData[1](error);
/******/ 									}
/******/ 								}
/******/ 							};// 调用 __webpack_require__.l
/******/ 							__webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
/******/ 						} else installedChunks[chunkId] = 0;
/******/ 					}
/******/ 				}
/******/ 		};
/******/ 		
/******/ 		// no prefetching
/******/ 		
/******/ 		// no preloaded
/******/ 		
/******/ 		// no HMR
/******/ 		
/******/ 		// no HMR manifest
/******/ 		
/******/ 		// no on chunks loaded
/******/ 		
/******/ 		// install a JSONP callback for chunk loading
/******/ 		var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ 			var [chunkIds, moreModules, runtime] = data;
/******/ 			// add "moreModules" to the modules object,
/******/ 			// then flag all "chunkIds" as loaded and fire callback
/******/ 			var moduleId, chunkId, i = 0;
/******/ 			if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ 				for(moduleId in moreModules) {
/******/ 					if(__webpack_require__.o(moreModules, moduleId)) {
/******/ 						__webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ 					}
/******/ 				}
/******/ 				if(runtime) var result = runtime(__webpack_require__);
/******/ 			}
/******/ 			if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ 			for(;i < chunkIds.length; i++) {
/******/ 				chunkId = chunkIds[i];
/******/ 				if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ 					installedChunks[chunkId][0]();
/******/ 				}
/******/ 				installedChunks[chunkId] = 0;
/******/ 			}
/******/ 		
/******/ 		}
/******/ 		
/******/ 		var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || [];
/******/ 		chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ 		chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ 	})();
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _test__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);

console.log("test", _test__WEBPACK_IMPORTED_MODULE_0__["default"]);

const loadSum = () => {__webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(__webpack_require__, 2)).then(module => {console.log(module.default(6, 9))})
}

const btn = document.getElementById("btn");
btn.addEventListener("click", loadSum, false);

})();

/******/ })()
; 

build/1.js

"use strict";
(self["webpackChunk"] = self["webpackChunk"] || []).push([[1],{

/***/ 2:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
const sum = (a, b) => {return a + b;
}

/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (sum);

/***/ })

}]); 

这里的示例,test.js 是通过静态 import 的方式引入的,sum.js 是通过动态 import 的方式引入的,可以看到一个很明显的区别:

  • test 模块一开始就放到了 __webpack_modules__中,而 sum 模块被单独打包成了一个独立的文件 1.js 中

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button id="btn">load sum</button><script src="./build/main.js"></script>
</body>
</html> 

由于这里涉及到 DOM 的一些操作,所以需要到浏览器中调试,这里给出两种方式:

1.npm i serve,然后在控制台执行 npx serve2.安装 VS Code 插件 Live Server,点击右下角 go live,打开对应的 html加载 sum 模块流程分析

sum.js 源码

import('./sum').then(module => {console.log(module.default(6, 9))
}) 

webpack 运行时代码,加载 sum 模块

__webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(__webpack_require__, 2)).then(module => {console.log(module.default(6, 9))
}) 

可以将上部分代码进行拆分一下,更有利于我们分析

const p1 = __webpack_require__.e(/* import() */ 1);
console.log("p1", p1);
const fn = __webpack_require__.bind(__webpack_require__, 2)
console.log("fn", fn);
// p1.then(fn) 这个时候才去执行 fn,拿到返回的 module.export,并且把这个结果再封装成一个 Promise 实例
const p2 = p1.then(fn);
console.log("p2", p2);
p2.then(module => {console.log(module.default(6, 9))
}) 

这是运行后的结果

这样拆解之后,可以看到 import('./sum') 转化为了 __webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(__webpack_require__, 2)) 做了如下一些事情:

1.__webpack_require__.e(/* import() */ 1)* 通过 Promise.all 返回一个 Promise 实例 p1
2.p1.then(__webpack_require__.bind(__webpack_require__, 2))* 当 p1 的状态变为 fulfilled ,执行 .then 中的函数 __webpack_require__(2),这个函数返回对应的 module.exports,被 then 处理后为一个 状态为 fulfilled的 Promise 实例,实例结果值就为 sum 模块导出值

然后再一步一步看看每个环节具体做了哪些事情

准备加载 1.js

__webpack_require__.e

输入:chunkId

输出:通过 Promise.all 返回一个 Promise 实例

作用:通过这个函数调用 __webpack_require__.f.j__webpack_require__.f.j 调用 __webpack_require__.l ,所以后面明确 __webpack_require__.f.j__webpack_require__.l 作用之后,就知道 __webpack_require__.e 作用是啥啦~

/******/ 	/* webpack/runtime/ensure chunk */
/******/ 	(() => {
/******/ 		__webpack_require__.f = {};
/******/ 		// This file contains only the entry chunk.
/******/ 		// The chunk loading function for additional chunks
/******/ 		__webpack_require__.e = (chunkId) => {// __webpack_require__.f -> { j: function } 
/******/ 			return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {	// 执行 __webpack_require__.f.j
/******/ 				__webpack_require__.f[key](chunkId, promises);
/******/ 				return promises;
/******/ 			}, []));
/******/ 		};
/******/ 	})(); 

这个时候必须要往下执行

__webpack_require__.f.j

输入:chunkId, promises

输出:undefined

作用:为加载 chunk 做一些准备

1.installedChunks 存放 已经加载了 和 正在加载 的 chunks,标记它们的加载状态
2.通过 __webpack_require__.p + __webpack_require__.u(chunkId) 得到需要加载 chunk 的 url
3.进行错误处理 -> 未成功加载到某个 chunk
4.调用 __webpack_require__.l

注:这里的分析省略了一些逻辑判断

/******/ 	/* webpack/runtime/jsonp chunk loading */
/******/ 	(() => {
/******/ 		// no baseURI
/******/ 		
/******/ 		// object to store loaded and loading chunks
/******/ 		// undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ 		// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded// installedChunks 存放 已经加载了 和 正在加载 的 chunks// 有几种取值// 0-> 已经加载了的 chunk// [resolve, reject, Promise] -> 正在加载的 chunk// undefined-> chunk 没有加载// null -> chunk preloaded/prefetched
/******/ 		var installedChunks = {
/******/ 			0: 0
/******/ 		};
/******/ 		
/******/ 		__webpack_require__.f.j = (chunkId, promises) => {
/******/ 				// JSONP chunk loading for javascript
/******/ 				var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
/******/ 				if(installedChunkData !== 0) { // 0 means "already installed".
/******/ 		
/******/ 					// a Promise means "currently loading".
/******/ 					if(installedChunkData) {
/******/ 						promises.push(installedChunkData[2]);
/******/ 					} else {
/******/ 						if(true) { // all chunks have JS
/******/ 							// setup Promise in chunk cache// installedChunkData 先赋值为 [resolve, reject]// 注意这里的 resolve,有用,后面在成功加载到 1.js 后就是执行这个 resolve(),改变了 promise 的状态
/******/ 							var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));// installedChunkData -> [resolve, reject, Promise]// 这个时候 promise 实例的状态为 pending
/******/ 							promises.push(installedChunkData[2] = promise);
/******/ 		
/******/ 							// start chunk loading// 得到需要加载chunk 的 url
/******/ 							var url = __webpack_require__.p + __webpack_require__.u(chunkId);
/******/ 							// create error before stack unwound to get useful stacktrace later// 进行错误处理 -> 未成功加载到某个 chunk
/******/ 							var error = new Error();
/******/ 							var loadingEnded = (event) => {
/******/ 								if(__webpack_require__.o(installedChunks, chunkId)) {
/******/ 									installedChunkData = installedChunks[chunkId];
/******/ 									if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
/******/ 									if(installedChunkData) {
/******/ 										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;
/******/ 										installedChunkData[1](error);
/******/ 									}
/******/ 								}
/******/ 							};// 调用 __webpack_require__.l
/******/ 							__webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
/******/ 						} else installedChunks[chunkId] = 0;
/******/ 					}
/******/ 				}
/******/ 		};
/******/ 		
/******/ 	})(); 

这个时候仍然需要继续往下分析

__webpack_require__.l

输入:url, done, key, chunkId

输出:undefined

作用:通过增加 script 标签的方式加载 chunk

/******/ 	/* webpack/runtime/load script */
/******/ 	(() => {
/******/ 		var inProgress = {};
/******/ 		// data-webpack is not used as build has no uniqueName
/******/ 		// loadScript function to load a script via script tag
/******/ 		__webpack_require__.l = (url, done, key, chunkId) => {
/******/ 			if(inProgress[url]) { inProgress[url].push(done); return; }
/******/ 			var script, needAttach;
/******/ 			if(key !== undefined) {
/******/ 				var scripts = document.getElementsByTagName("script");
/******/ 				for(var i = 0; i < scripts.length; i++) {
/******/ 					var s = scripts[i];
/******/ 					if(s.getAttribute("src") == url) { script = s; break; }
/******/ 				}
/******/ 			}
/******/ 			if(!script) {
/******/ 				needAttach = true;
/******/ 				script = document.createElement('script');
/******/ 		
/******/ 				script.charset = 'utf-8';
/******/ 				script.timeout = 120;
/******/ 				if (__webpack_require__.nc) {
/******/ 					script.setAttribute("nonce", __webpack_require__.nc);
/******/ 				}
/******/ 		
/******/ 				script.src = url;
/******/ 			}
/******/ 			inProgress[url] = [done];
/******/ 			var onScriptComplete = (prev, event) => {
/******/ 				// avoid mem leaks in IE.
/******/ 				script.onerror = script.onload = null;
/******/ 				clearTimeout(timeout);
/******/ 				var doneFns = inProgress[url];
/******/ 				delete inProgress[url];// 注意这里,当通过 script 加载 chunk 完成之后,会删除这个 script 标签
/******/ 				script.parentNode && script.parentNode.removeChild(script);
/******/ 				doneFns && doneFns.forEach((fn) => (fn(event)));
/******/ 				if(prev) return prev(event);
/******/ 			};
/******/ 			var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
/******/ 			script.onerror = onScriptComplete.bind(null, script.onerror);
/******/ 			script.onload = onScriptComplete.bind(null, script.onload);
/******/ 			needAttach && document.head.appendChild(script);
/******/ 		};
/******/ 	})(); 

needAttach && document.head.appendChild(script); 这段代码执行前:

needAttach && document.head.appendChild(script); 这段代码执行后:

如图,__webpack_require__.l 函数执行完,head 中多了 <script charset="utf-8" src="http://localhost:3003/build/1.js"></script>,这个时候就开始加载 1.js 了

加载并执行 1.js

"use strict";
(self["webpackChunk"] = self["webpackChunk"] || []).push([[1],{

/***/ 2:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
const sum = (a, b) => {return a + b;
}

/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (sum);

/***/ })

}]); 

self["webpackChunk"] || []).push 在最开始的时候的时候就定义了

/******/ 		var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || [];
/******/ 		chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ 		chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); 

于是就走进 webpackJsonpCallback 这个函数中


webpackJsonpCallback

输入:parentChunkLoadingFunction, data

输出:undefined

作用:

1.将加载到的 sum 模块放到 __webpack_modules__ 中* __webpack_require__.m[moduleId] = moreModules[moduleId];
2.将 p1 Promise 实例状态变为 fulfilled* installedChunks[chunkId][0]();

注意:__webpack_require__.m = __webpack_modules__; 说明它们都指向同一个内存地址,所以 __webpack_require__.m 改变,__webpack_modules__也会跟着改变

/******/ 		// install a JSONP callback for chunk loading
/******/ 		var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ 			var [chunkIds, moreModules, runtime] = data;
/******/ 			// add "moreModules" to the modules object,
/******/ 			// then flag all "chunkIds" as loaded and fire callback
/******/ 			var moduleId, chunkId, i = 0;
/******/ 			if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ 				for(moduleId in moreModules) {
/******/ 					if(__webpack_require__.o(moreModules, moduleId)) {
/******/ 						__webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ 					}
/******/ 				}
/******/ 				if(runtime) var result = runtime(__webpack_require__);
/******/ 			}
/******/ 			if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ 			for(;i < chunkIds.length; i++) {
/******/ 				chunkId = chunkIds[i];
/******/ 				if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ 					installedChunks[chunkId][0]();
/******/ 				}
/******/ 				installedChunks[chunkId] = 0;
/******/ 			}
/******/ 		
/******/ 		} 

加载 sum 模块

p1.then(__webpack_require__.bind(__webpack_require__, 2))

通过上述处理之后,__webpack_modules__已经有 sum 模块了

也就是

// __webpack_modules__ 
([
/* 0 */,
/* 1 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ('test');

/***/ }),
/* 2 */ 
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
const sum = (a, b) => {return a + b;
}

/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (sum);

/***/ })
/******/ 	]);
/************************************************************************/ 

小结

简单总结一下:__webpack_modules__没有一开始就存放动态加载的模块,而是在满足设定的条件后(比如本示例是点击 load sum 按钮),通过 JSONP 的方式加载动态模块,并且通过 webpackJsonpCallback(JSONP callback)将加载的模块放到 __webpack_modules__中,并将 __webpack_require__.e 返回的 Promise 实例状态变为 fulfilled,然后就可以通过 __webpack_require__ 加载模块了。

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/183600.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安装mysql的保姆级教程

安装mysql的保姆级教程&#xff1a; 1.准备的条件 已下载mysql应用软件 my.ini文件&#xff08;见2&#xff09; 2.设置my.ini文件 &#xff08;1&#xff09;my.ini文件内容&#xff1a; [mysqld] # 设置3306端口 port3306 # 设置mysql的安装目录 ----------是你的文件路径…

TCP/IP网络编程——基于 UDP 的服务端/客户端

完整版文章请参考&#xff1a; TCP/IP网络编程完整版文章 文章目录第 6 章 基于 UDP 的服务端/客户端6.1 理解 UDP6.1.1 UDP 套接字的特点6.1.2 UDP 的工作原理6.1.3 UDP 的高效使用6.2 实现基于 UDP 的服务端/客户端6.2.1 UDP 中的服务端和客户端没有连接6.2.2 UDP 服务器和客…

业务流程软件的优点和对企业的好处

我们都知道&#xff0c;CRM客户管理软件可以为企业识别意向客户&#xff0c;带来更多业绩。那么在处理业务的过程中&#xff0c;一套自带业务流程管理的CRM软件是否重要&#xff1f;下面我们来说说企业使用业务流程管理软件的好处&#xff0c;您就清楚问题的答案了。 1、减少错…

【项目精选】基于 Spring Boot + Mybatis Plus + MySQL 的社区居民联系方式管理系统

项目简介 此系统使用 Spring Boot Mybatis Plus Spring Security React Ant Design Pro 架构编写。数据库采用 MySQL&#xff0c;提供强大的、安全的和完整的管理社区居民的信息的功能。 安全性 此系统在系统层面提供了众多的安全特性&#xff0c;产品安全无忧。这些特性…

【高并发】- 生产级系统搭建 - 2

前言 本章讲解高并发系统中常见概念及相关设计的方案&#xff0c;目的是让小伙伴都了解高并发系统中&#xff0c;每个环节所涉及到的相关概念。帮助大家更好地理解和掌握高并发系统中的场景及设计思想。 1. 常见高并发系统架构图&#xff08;这里以秒杀系统为例&#xff09; 上…

国电投-光伏电站人工智能运维大数据处理分析比赛(记录)

前言 1-1 简介 DataFountain平台举办的比赛&#xff0c;赛题&#xff1a;光伏电站人工智能运维大数据处理分析。以下是比赛链接&#xff1a;光伏电站人工智能运维大数据处理分析 Competitions - DataFountain 1-2 任务背景 在分析光伏发电原理的基础上&#xff0c;论证了辐照…

虹科分享 | 2022年传感器事业部文章精选

2022年 文章精选 精选案例文章 虹科案例 | HK-Micronor光纤传感器应用领域介绍&#xff08;上&#xff09; 虹科案例 | HK-Micronor光纤传感器应用领域介绍&#xff08;下&#xff09; 虹科案例 | 如何更加准确的表征罐箱内燃油的质量规格&#xff1f; 虹科案例 | 监测各种…

java Vue+Springboot读书学习笔记共享平台

读书笔记共享平台的设计基于现有的网络平台&#xff0c;可以实现用户管理及数据信息管理&#xff0c;方便管理员对后台进行管理有详细的了解及统计分析&#xff0c;随时查看信息状态。 系统功能设计是在系统开发和设计思想的总体任务的基础上完成的。该系统的主要任务是实现读书…

CnOpenData中国保险机构网点全集数据

一、数据简介 改革开放以来&#xff0c;中国保险行业飞速增长&#xff0c;在补偿灾害损失、维护社会安定、支持中国的经济建设等方面发挥了重要作用。整个行业的突飞猛进体现在三个方面&#xff1a; 一是保险机构数量增长迅速。中国保险公司的数量从1980年的1家迅速增加至200多…

【云原生】Prometheus之图形化界面grafana与服务发现部署

内容预知 前言 1. 部署 Grafana 1.1 grafana的下载与安装 (1)安装grafana &#xff08;2&#xff09;配置数据源 &#xff08;3&#xff09;导入 grafana 监控面板 &#xff08;4&#xff09;删除模板操作 4.2 grafana的中文插件安装 2. 部署 Prometheus 服务发现 2.1…

C语言中二维数组的基本使用 定义 赋值读写指定元素的值 作为函数参数传递的注意点

文章目录问题依次解决C语言中二维数组如何定义、如何一次性赋值&#xff1f;如何使用 sizeof() 计算二维数组的行数、列数&#xff1f;【与定义数组的地方&#xff0c;在同一作用域内可用】如何读写指定位置的元素&#xff1f;【不同作用域&#xff0c;有两种方式】不同作用域内…

Git(见资源)

Git的概念【1】Git技术&#xff1a;公司必备&#xff0c;一定要会 【2】Git概念&#xff1a; Git是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小型到大型的项目。【3】什么是版本控制&#xff1f; 版本控制是一种记录一个或若干文件内容变化&#…

BGP基础实验(华为)

题目&#xff1a; 思路&#xff1a; 该题分为三个AS区域&#xff0c;并且三个区别间分别使用不同的路由&#xff0c;EBGP,IBGP,OSFP连接等&#xff0c;其中AS1与AS2之间使用的是EBGP连接&#xff0c;这点需要EBGP的命令来进行实现&#xff0c;AS2中使用的OSPF&#xff0c;AS2&a…

不规范使用ThreadLocal导致的bug,说多了都是泪

ThreadLocal一般用于线程间的数据隔离&#xff0c;通过将数据缓存在ThreadLocal中&#xff0c;可以极大的提升性能。但是&#xff0c;如果错误的使用Threadlocal&#xff0c;可能会引起不可预期的bug&#xff0c;以及造成内存泄露。 因为线程重用导致的信息错乱的bug 有时我们…

一起自学SLAM算法:11.2 环境感知

连载文章&#xff0c;长期更新&#xff0c;欢迎关注&#xff1a; 环境感知就是机器人利用传感器获取自身及环境状态信息的过程&#xff0c;自主导航机器人的环境感知主要包括实时定位、环境建模、语义理解等&#xff0c;下面具体讨论。 11.2.1 实时定位 定位其实就是在回答图…

BI技巧丨近两年及当年月份数据汇总

BOSS&#xff1a;白茶&#xff0c;有个需求&#xff0c;不知道你能不能做&#xff1f; 白茶&#xff1a;不能&#xff01; BOSS&#xff1a;我还没说呢&#xff0c;小伙砸&#xff01;做了加钱&#xff01; 白茶&#xff1a;BOSS您吩咐&#xff01; BOSS&#xff1a;是这样的&a…

C语言开发基于RT-Thread家庭安全环境检测系统源码,RTT设计大赛

基于RT-Thread家庭安全环境检测 简介 基于RT-Thread和中蓝讯科的AB32VG1开发板实现的家庭安全检测功能&#xff0c;主要包含如下功能&#xff1a; 1、基于RT-Thread操作系统的按键组件&#xff0c;音频播放组件等&#xff1b; 2、基于AB32VG1开发板的语音播放功能&#xff1b…

BlackByte勒索软件开始使用新的数据泄露工具ExByte

BlackByte 勒索软件在 2021 年被首次发现&#xff0c;随后不断发现其变种。BlackByte 勒索软件不仅使用双重勒索&#xff0c;还运营着勒索软件即服务&#xff08;RaaS&#xff09;。最近&#xff0c;研究人员发现 BlackByte 开始使用名为 ExByte 的数据泄露工具来窃取受害者的数…

什么品牌的蓝牙耳机音质好?四款高音质蓝牙耳机推荐

随着时代的发展&#xff0c;蓝牙耳机的使用频率越来越高&#xff0c;在日常生活中随处可见的戴蓝牙耳机的人。或是听音乐&#xff0c;或是追剧&#xff0c;或是玩游戏等等。在现如今众多的蓝牙耳机品牌当中&#xff0c;什么品牌的蓝牙耳机音质好&#xff1f;下面&#xff0c;我…

基于Yolo实现的交通路况汽车识别 附完整代码(使用Keras框架)

一、问题描述 假设你现在在做自动驾驶的汽车,你想着首先应该做一个汽车检测系统,为了搜集数据,你已经在你的汽车前引擎盖上安装了一个照相机,在你开车的时候它会每隔几秒拍摄一次前方的道路。 您已经将所有这些图像收集到一个文件夹中,并通过在您找到的每辆车周围画边界框…