代码执行时机将决定着是否可以正常执行,当依赖文件没加载完成就开始执行、使用对应模块,那么将会致使执行异常。这在 “存在资源加载失败时,加载重试影响原来文件的执行顺序” 的场景下尤其常见。react
webpack 构建除了进行模块依赖管理,实际上,也自然地管理了 entry 与 chunk 多文件的执行时机,但缺乏了对 external 文件管理,当 external 文件加载失败或未完成时,执行、使用对应模块一样将致使异常。为此,wait-external-webpack-plugin 应运而生,以 webpack 插件的形式,补充 external 的执行管理。本文将进行简要说明。webpack
将 webpack 打包后的代码进行简化,其实就是一个当即调用函数;传入 “模块”,使用 webpack_require 进行调用。在单文件下,文件加载后将当即执行业务逻辑。web
(function(modules) { // webpackBootstrap
function __webpack_require__(moduleId) {
// ...
// 执行模块代码
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
}
// 引用入口
return __webpack_require__(__webpack_require__.s = "./src/entryB.js");
})({
"./entryB.js": (function(module, __webpack_exports__, __webpack_require__) {
// ...
})
});
复制代码
为了 “抽取公共模块进行单独打包避免重复加载” 或 “增长并发请求数减小总加载时间” 等缘由,通常会将代码拆分红多文件,可以使用以下形式:json
使用 webpack 的 splitChunks 插件,将代码拆分红多个 chunk 文件; 经过配置 external,将第三方库单独加载; 拆分红多个文件后,为了不业务逻辑执行时相关文件还没加载完成致使执行出错,须要等待相关文件都加载完成后再开始执行。缓存
2.1 等待 entry 与 chunk 文件都加载完成
entry 与 其余 chunk 文件的 “等待-执行” 的逻辑,webpack 其实已经帮咱们自动生成了。bash
2.1.1 在生成的 entry 文件中并发
// # entry.js
// 声明依赖列表
deferredModules.push(["./src/entryA.js","commons"]);
// 缓存已完成的加载
var installedChunks = {
"entryA": 0
};
function webpackJsonpCallback(data) {
// 加载后标记完成
installedChunks[chunkId] = 0;
}
// 检查是否都加载完成,如是,则开始执行业务逻辑
function checkDeferredModules() {
// 判断 installedChunks 是否完整
// ...
if(fulfilled) {
// 全部都加载,开始执行
result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
}
}
// 提供给 chunk 的全局回调方法
var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
jsonpArray.push = webpackJsonpCallback;
复制代码
2.1.2 在生成的 chunk 文件中
chunk 文件加载后,正常状况下将调用 entry 提供的全局回调方法,标记加载完成。而当 chunk 文件先于 entry 加载完成,则会先缓存记录,等 entry 文件加载后读取缓存并将其标记完成。函数
// # chunk.js
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["commons"],{
"./src/moduleA.js": (function(module, __webpack_exports__, __webpack_require__) {
// ...
})
}]);
复制代码
2.1.3 小结
基于以上分析,能够看出 entry 和 chunk 文件加载顺序不会影响执行时机,只有在都加载完成后,才会执行业务逻辑。以下图示jsonp
"react": (function(module, exports) {
eval("(function() { module.exports = window[\"React\"]; }());");
})
复制代码
2.2.1 添加等待 external 文件加载完成再执行逻辑
为了不使用时出错,在执行前需先保证 external 文件已经加载完成。处理方式以下ui
示意代码:
(function () {
var entryInit = function () {
(function(modules) {
// webpackBootstrap
// ...
})({})
};
if (window["React"]) {
entryInit();
} else {
var hasInit = false;
var callback = function () {
if(hasInit) return;
if (window["React"]) {
hasInit = true;
document.removeEventListener('load', callback, true);
entryInit();
}
};
document.addEventListener('load', callback, true);
}
})();
复制代码
2.2.2 “自动” 生成等待 external 文件加载完成再执行逻辑
等待 external 加载完成逻辑是统一的,差别在于依赖的 external 或有不一样。为了不手动添加出错,咱们能够经过以 webpack 插件的形式自动分析依赖,并生成相关代码。
具体实现可见插件 wait-external-webpack-plugin
经过 wait-external-webpack-plugin 插件,可以自动生成等待依赖的 external 文件加载完成再执行逻辑,对开发者透明,保证文件对正常执行。
欢迎使用,欢迎任何意见或建议,谢谢。
转载自AlloyTeam:www.alloyteam.com/2019/07/wai…