IIFE 传入的 modules 对象里多了一个键值对,对应着新模块 src/utils/math.js,这和我们在源代码中拆分的模块互相呼应。然而,有了 modules 只是第一步,这份文件最终达到的效果应该是让各个模块按开发者编排的顺序运行。
探究 webpackBootstrap
接下来看看 webpackBootstrap 函数中有些什么:
- // webpackBootstrap
- (function(modules){
- // 缓存 __webpack_require__ 函数加载过的模块
- var installedModules = {};
- /**
- * Webpack 加载函数,用来加载 webpack 定义的模块
- * @param {String} moduleId 模块 ID,一般为模块的源码路径,如 "./src/index.js"
- * @returns {Object} exports 导出对象
- */
- function __webpack_require__(moduleId) {
- // ...
- }
- // 在 __webpack_require__ 函数对象上挂载一些变量及函数 ...
- // 传入表达式的值为 "./src/index.js"
- return __webpack_require__(__webpack_require__.s = "./src/index.js");
- })(/* modules */);
可以看到其实主要做了两件事:
- 定义一个模块加载函数 __webpack_require__。
- 使用加载函数加载入口模块 "./src/index.js"。
整个 webpackBootstrap 中只出现了入口模块的影子,那其他模块又是如何加载的呢?我们顺着 __webpack_require__("./src/index.js") 细看加载函数的内部逻辑:
- function __webpack_require__(moduleId) {
- // 重复加载则利用缓存
- if (installedModules[moduleId]) {
- return installedModules[moduleId].exports;
- }
- // 如果是第一次加载,则初始化模块对象,并缓存
- var module = installedModules[moduleId] = {
- i: moduleId, // 模块 ID
- l: false, // 模块加载标识
- exports: {} // 模块导出对象
- };
- /**
- * 执行模块
- * @param module.exports -- 模块导出对象引用,改变模块包裹函数内部的 this 指向
- * @param module -- 当前模块对象引用
- * @param module.exports -- 模块导出对象引用
- * @param __webpack_require__ -- 用于在模块中加载其他模块
- */
- modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
- // 模块加载标识置为已加载
- module.l = true;
- // 返回当前模块的导出对象引用
- return module.exports;
- }
首先,加载函数使用了闭包变量 installedModules,用来将已加载过的模块保存在内存中。接着是初始化模块对象,并把它挂载到缓存里。然后是模块的执行过程,加载入口文件时 modules[moduleId] 其实就是 ./src/index.js 对应的模块函数。执行模块函数前传入了跟模块相关的几个实参,让模块可以导出内容,以及加载其他模块的导出。最后标识该模块加载完成,返回模块的导出内容。
根据 __webpack_require__ 的缓存和导出逻辑,我们得知在整个 IIFE 运行过程中,加载已缓存的模块时,都会直接返回 installedModules[moduleId].exports,换句话说,相同的模块只有在第一次引用的时候才会执行模块本身。
模块执行函数
__webpack_require__ 中通过 modules[moduleId].call() 运行了模块执行函数,下面我们就进入到 webpackBootstrap 的参数部分,看看模块的执行函数。
- /*** 入口模块 ./src/index.js ***/
- "./src/index.js": (function (module, __webpack_exports__, __webpack_require__) {
- "use strict";
- // 用于区分 ES 模块和其他模块规范,不影响理解 demo,战略跳过。
- __webpack_require__.r(__webpack_exports__);
- /* harmony import */
- // 源模块代码中,`import {plus} from ./utils/math.js ;` 语句被 loader 解析转化。
- // 加载 "./src/utils/math.js" 模块,
- var _utils_math_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/utils/math.js");
- console.log( Hello webpack! );
- console.log( 1 + 2: , Object(_utils_math_js__WEBPACK_IMPORTED_MODULE_0__["plus"])(1, 2));
- }),
-
-
- "./src/utils/math.js": (function (module, __webpack_exports__, __webpack_require__) {
- "use strict";
- __webpack_require__.r(__webpack_exports__);
- /* harmony export (binding) */
- // 源模块代码中,`export` 语句被 loader 解析转化。
- __webpack_require__.d(__webpack_exports__, "plus", function () {
- return plus;
- });
- const plus = (a, b) => {
- return a + b;
- };
- })
(编辑:ASP站长网)
|