webpack 动态导入

加载 chunks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
__webpack_require__.e = function requireEnsure(chunkId) {
// 1、缓存查找 从缓存 installedChunks 中查找是否有缓存模块,如果缓存标识为0,则表示模块已加载过,直接返回 promise;
var installedChunkData = installedChunks[chunkId];
if (installedChunkData === 0) {
return new Promise(function(resolve) {
resolve();
});
}
// 2、 如果缓存为数组,表示缓存正在加载中,则返回缓存的 promise 对象
if (installedChunkData) {
return installedChunkData[2];
}
// 3、没有缓存,则创建一个 promise,并将 promise和resolve、reject 缓存在 installedChunks 中
var promise = new Promise(function(resolve, reject) {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
installedChunkData[2] = promise;
// 4、加载模块 发送 JSONP 请求
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
script.charset = "utf-8";
script.async = true;
script.timeout = 120000;
if (__webpack_require__.nc) {
script.setAttribute("nonce", __webpack_require__.nc);
}
script.src =
__webpack_require__.p +
"" +
({ "0": "foo" }[chunkId] || chunkId) +
".bundle.js";
// 5、异常处理 添加 script 标签 onload、onerror 事件,如果超时或者模块加载失败,则会调用 reject 返回模块加载失败异常
var timeout = setTimeout(onScriptComplete, 120000);
script.onerror = script.onload = onScriptComplete;
function onScriptComplete() {
// avoid mem leaks in IE.
script.onerror = script.onload = null;
clearTimeout(timeout);
var chunk = installedChunks[chunkId];
if (chunk !== 0) {
if (chunk) {
chunk[1](new Error("Loading chunk " + chunkId + " failed."));
}
installedChunks[chunkId] = undefined;
}
}
head.appendChild(script);
// 6、返回 promise
return promise;
};

执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
window["webpackJsonp"] = function webpackJsonpCallback(
chunkIds,
moreModules,
executeModules
) {
var moduleId,
chunkId,
i = 0,
resolves = [],
result;
// 7、根据 chunkId 收集模块 resolve
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if (installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0]);
}
installedChunks[chunkId] = 0;
}
// 8、将 chunks 模块放到 modules
for (moduleId in moreModules) {
if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules[moduleId] = moreModules[moduleId];
}
}
if (parentJsonpFunction)
parentJsonpFunction(chunkIds, moreModules, executeModules);
// 9、resolve import 执行回调
while (resolves.length) {
resolves.shift()();
}
};

总的流程

  • __webpack_require__.e 开始加载异步 chunks 将异步回调放入 installedChunks 发送 JSONP 请求
  • window["webpackJsonp"] 根据 chunkIds 收集 resolve ,将 chunks 模块 放到 modules 中,执行 resolve ,加载 model