以webpack@4.46.0 官网首页的代码为例,分析webpack编译为web环境的代码(webpack默认构建目标为web)
总观,编译后的代码为立即执行函数
函数的参数为对象,对象的key就是两个文件的相对路径,value为函数index.js 跟bar.js放在eval内,为了方便阅读把eval中的函数拿出来
{
"./src/bar.js": function barWrapper(
module,
__webpack_exports__,
__webpack_require__
) {
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "default", function () { // 将bar函数挂载到__webpack_require__中定义的exports对象上,从而保证被调用模块可以拿到bar函数
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__
函数中生成,每执行一次__webpack_require__
函数也就是用__webpack_require__
调用一次模块,exports都是新的对象(即__webpack_exports__
)
总结:
__webpack_require__
函数中定义exports对象,根据moduleId去调用对应的模块,将_webpack_require__
函数传入模块,从而保证该模块可以调用其他模块,也将__webpack_exports__
传入模块,从而将模块中定义的函数变量挂载到__webpack_require__
定义的exports对象中,从而在调用__webpack_require__
模块的地方可以拿到被调用模块内定义的变量跟函数。这么理解下来可以知道,__webpack_require__
传递到每个模块是必要的,但是为啥要将__webpack_exports__
每个模块,完全可以在每个模块中定义一个对象返回出来,这样调用者就可以拿到被调用模块的变量 函数了。不是很明白,有清楚的,可以告知
看完代码也可以回答一个问题:webpack是怎样实现模块的依赖的?
将文件的相对路径作为模块的id ,通过最外层的立即执行函数避免模块内变量污染全局,用_webpack_require__
函数来实现模块的相关引用,每个模块都是包裹在函数里,通过传入的__webpack_exports__
对象将模块内的变量函数暴露给调用模块,最终调用模块就可以拿到被调用模块内部的函数 变量了。说白了就是用函数从模拟模块,将每个模块的代码包裹在一个函数内,通过__webpack_exports__
将其暴露给调用模块。