测试代码:
打包后的整体代码:
由上面可以看出,
- 最外层是一个自执行匿名函数, 形成封闭的作用域
- 一个
__webpack_modules__
对象 - 一个
__webpack_module_cache__
对象 - 一个
__webpack_require__
函数 - 三个匿名自执行函数
- 加载入口文件
webpack_modules
__webpack_modules__
是一个文件路径作为key,函数作为value,对应文件内容放在函数体内。
js
var __webpack_modules__ = {
/**
* 看到__webpack_require__函数,就知道这三个参数是啥了
* @param {*} __unused_webpack_module 就是创建的新模块,不在缓存中
* @param {*} __webpack_exports__ 新模块的exports对象或者缓存中exports对象
* @param {*} __webpack_require__ 模块加载函数
*/
"./src/index.js": (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// 给当前的模块添加标识,这是一个ES Module
__webpack_require__.r(__webpack_exports__);
// 加载当前模块,具体做了啥操作,可以看__webpack_require__内部实现
var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/utils.js");
// 当走完上一步过后,_utils__WEBPACK_IMPORTED_MODULE_0__这个对象里面就包含了add方法了
// 执行add方法
const sum = (0, _utils__WEBPACK_IMPORTED_MODULE_0__.add)(1, 2);
// 打印结果
console.log(sum);
},
"./src/utils.js": (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// 给当前的模块添加表示, 这是一个ES Module
_webpack_require__.r(__webpack_exports__);
// 下面介绍了,d方法是给新模块的exports添加属性的,属性的来源就是代码中最后export对象
__webpack_require__.d(__webpack_exports__, { add: () => add });
const add = (a, b) => {
return a + b;
};
},
};
webpack_module_cache
被加载过模块的缓存集合
存放已经加载过的模块返回的值,可能一个模块被多个地方使用,每次加载前过来检查下,如果有,说明之前被加载过了,那么可以直接返回结果,避免模块重复加载。
webpack_require
用于加载和执行模块的核心函数,返回新模块的exports对象
。
js
function __webpack_require__(moduleId) {
// 传入一个模块ID,其实就是模块对应的路径,例如: ./src/index.js
// 判断当前这个模块是否在缓存中,如果在的话,直接从缓存中拿到返回值
var cachedModule = __webpack_module_cache__[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// 创建一个新的模块,并且添加到缓存中,key为模块的路径,value为{ exports: {} }
var module = (__webpack_module_cache__[moduleId] = {
exports: {},
});
// 加载和执行模块中的代码
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
// Return the exports of the module
return module.exports;
}
三个自执行匿名函数
js
/* webpack/runtime/define property getters */
(() => {
// define getter functions for harmony exports
__webpack_require__.d = (exports, definition) => {
for (var key in definition) {
if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
}
}
};
})();
/* webpack/runtime/hasOwnProperty shorthand */
(() => {
__webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
})();
/* webpack/runtime/make namespace object */
(() => {
// define __esModule on exports
__webpack_require__.r = (exports) => {
if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
}
Object.defineProperty(exports, "__esModule", { value: true });
};
})();
给__webpack_require__函数对象添加d方法
给模块的exports属性中添加代码中export的属性
js
/**
* @param {*} exports __webpack_require__中返回的exports对象 {}
* @param {*} definition 代码中最后export
*/
__webpack_require__.d = (exports, definition) => {
// 遍历代码中export对象中所有的属性
for (var key in definition) {
// o方法是判断对象中是否存在某个属性
// 代码中最后export包含这个属性,但是新的模块exports不包含,因此要给exports添加这个属性
if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
}
}
};
解释:__webpack_require__
不是创建出一个新的模块并返回对应的exports属性了吗,而开发时候文件会存在export {name: 'chenjiang', age: 26}
导出代码,现在就是要把代码中导出的属性和属性值存放到新的模块exports中。
给__webpack_require__函数对象添加o方法
其实就是判断对象是否存在某个属性
javascript
__webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
给__webpack_require__函数对象添加r方法
给当前模块做个标识ES Module。
js
__webpack_require__.r = (exports) => {
if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
}
Object.defineProperty(exports, "__esModule", { value: true });
};
启动函数
直接加载执行入口文件
js
var __webpack_exports__ = __webpack_require__("./src/index.js");
参考文档: