代碼執行時機將決定着是否可以正常執行,當依賴文件沒加載完成就開始執行、使用對應模塊,那麼將會致使執行異常。這在 「存在資源加載失敗時,加載重試影響原來文件的執行順序」 的場景下尤其常見。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…