以webpack@4.46.0 官網(wǎng)首頁的代碼為例,分析webpack編譯為web環(huán)境的代碼(webpack默認構(gòu)建目標為web)
總觀倔丈,編譯后的代碼為立即執(zhí)行函數(shù)
函數(shù)的參數(shù)為對象需五,對象的key就是兩個文件的相對路徑警儒,value為函數(shù)index.js 跟bar.js放在eval內(nèi),為了方便閱讀把eval中的函數(shù)拿出來
{
"./src/bar.js": function barWrapper(
module,
__webpack_exports__,
__webpack_require__
) {
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "default", function () { // 將bar函數(shù)掛載到__webpack_require__中定義的exports對象上蜀铲,從而保證被調(diào)用模塊可以拿到bar函數(shù)
return bar;
});
function bar() {
console.info("xx");
}
},
"./src/index.js": function indexWrapper(
module,
__webpack_exports__,
__webpack_require__
) {
__webpack_require__.r(__webpack_exports__);
var _bar__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/bar.js");
Object(_bar__WEBPACK_IMPORTED_MODULE_0__["default"])();
},
};
__webpack_require__
的定義
function __webpack_require__(moduleId) {
// Check if module is in cache
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
} // Create a new module (and put it into the cache)
var module = (installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}, // 定義exports空對象
}); // Execute the module function
modules[moduleId].call(
module.exports,
module,
module.exports, // 將exports
__webpack_require__
); // Flag the module as loaded
module.l = true; // Return the exports of the module
return module.exports; // 返回exports對象
} // expose the modules object (__webpack_modules__)
__webpack_require__.d
用來在exports對象上定義屬性
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
enumerable: true,
get: getter,
});
}
}; // define __esModule on exports
exports 在__webpack_require__
函數(shù)中生成变姨,每執(zhí)行一次__webpack_require__
函數(shù)也就是用__webpack_require__
調(diào)用一次模塊厌丑,exports都是新的對象(即__webpack_exports__
)
總結(jié):
__webpack_require__
函數(shù)中定義exports對象怒竿,根據(jù)moduleId去調(diào)用對應的模塊,將_webpack_require__
函數(shù)傳入模塊耕驰,從而保證該模塊可以調(diào)用其他模塊,也將__webpack_exports__
傳入模塊饭弓,從而將模塊中定義的函數(shù)變量掛載到__webpack_require__
定義的exports對象中弟断,從而在調(diào)用__webpack_require__
模塊的地方可以拿到被調(diào)用模塊內(nèi)定義的變量跟函數(shù)趴生。這么理解下來可以知道,__webpack_require__
傳遞到每個模塊是必要的舍咖,但是為啥要將__webpack_exports__
每個模塊,完全可以在每個模塊中定義一個對象返回出來排霉,這樣調(diào)用者就可以拿到被調(diào)用模塊的變量 函數(shù)了攻柠。不是很明白后裸,有清楚的微驶,可以告知
看完代碼也可以回答一個問題:webpack是怎樣實現(xiàn)模塊的依賴的?
將文件的相對路徑作為模塊的id 苟耻,通過最外層的立即執(zhí)行函數(shù)避免模塊內(nèi)變量污染全局扶檐,用_webpack_require__
函數(shù)來實現(xiàn)模塊的相關引用款筑,每個模塊都是包裹在函數(shù)里,通過傳入的__webpack_exports__
對象將模塊內(nèi)的變量函數(shù)暴露給調(diào)用模塊杈湾,最終調(diào)用模塊就可以拿到被調(diào)用模塊內(nèi)部的函數(shù) 變量了攘须。說白了就是用函數(shù)從模擬模塊,將每個模塊的代碼包裹在一個函數(shù)內(nèi)叫挟,通過__webpack_exports__
將其暴露給調(diào)用模塊限煞。