探究 webpack 如何實現模塊化加載
最近稍稍比較忙,但還是要騰出時間來寫寫博客,博客真的是個好東西,只要你堅持。這次主要講講 webpack 打包後的代碼,分析他是如何實現模塊化(同步)加載模塊的,然後下次再講講如何按需(異步)加載模塊。
一、webpack 模塊化
關於模塊化,可以看看我之前的總結博客 js模塊化進程
總結一下,就是按照功能將一個項目切分成許多部分單獨開發,然後再組裝起來,每一個部分即爲模塊。
但是不管使用 require 還是 ES6 的 import ,最終都是經過 webpack 編譯,模擬該行爲,最後得到可執行代碼。
二、webpack 同步加載源碼
(1)源碼
我們直接用一個例子展示,使用打包配置
module.exports = {
mode: "development",
devtool: "source-map",
...
}
主文件:
import func from './func.js'
func.add(1,2)
引用文件:
class func{
add(val1,val2){
return val1 + val2
}
}
export default new func()
打包後源碼爲:
(function (modules) { // 立刻執行函數 webpackBootstrap
var installedModules = {}; //緩存模塊
function __webpack_require__(moduleId) { //模塊加載函數
......
}
......
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})({
({ //引用文件
"./src/func.js":
(function (module, __webpack_exports__, __webpack_require__) {
class func {
add(val1, val2) {
return val1 + val2
}
}
)}
__webpack_exports__["default"] = (new func());
}),
({ //主文件
"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {
var _func_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/func.js");
_func_js__WEBPACK_IMPORTED_MODULE_0__["default"].add(1, 2)
})
});
1.使用了立刻執行函數的形式(webpackBootstrap),密閉空間。傳入一個對象 modules ,以文件名爲 key,value 是各個模塊內的代碼。
2.立刻執行函數內:
- installedModules 對象用於緩存模塊
- _webpack_require_ 是一個模塊加載函數,模擬 require 和 import
- 最後加載了主文件代碼,主文件執行了 webpack_require 又引入了引用文件
(2)_webpack_require_ 如何實現模塊加載
function __webpack_require__(moduleId) {
//使用緩存對象輸出模塊
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
//沒有緩存則創建新模塊
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
//執行模塊
modules[moduleId].call(module.exports, module,module.exports, __webpack_require__);
//模塊加載完成標誌
module.l = true;
//返回輸出模塊
return module.exports;
}
- 首先使用緩存看能否對象輸出模塊,緩存的目的其實就是加載時加速。
- 沒有緩存則在對象內創建該模塊,設置 i(模塊ID),l(是否加載完成),exports(一個引用,指向模塊的導出對象)
- 然後就是執行該模塊,通過 call 把 this 綁定在輸出模塊內。
同時觀察一下引用文件,它是通過 export 輸出內容的,而 export 正就是傳入該模塊的第三個參數 module.export。並且上述函數綁定的執行環境也是這個輸出模塊。通過相互循環引用,達成了拆分文件模塊後,調用時執行環境不變的效果。
當然,webpack 遠不止做了這些操作,本次只講了一個簡化的主流程。方便大家理解這個過程。