文章内容:用 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 serve
2.安装 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道面试题,并对每个问题作出了回答和解析。
有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享
部分文档展示:
文章篇幅有限,后面的内容就不一一展示了
有需要的小伙伴,可以点下方卡片免费领取