webpack打包文件分析

测试代码:

打包后的整体代码:

由上面可以看出,

  • 最外层是一个自执行匿名函数, 形成封闭的作用域
  • 一个__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");

参考文档:

www.cnblogs.com/gaokai/p/15...

相关推荐
谢尔登3 分钟前
【React】使用 useContext + useReducer 实现一个轻量的状态管理库
前端·javascript·react.js
Bee.Bee.8 分钟前
vue3提供的hook和通常的函数有什么区别
前端·javascript·vue.js
元拓数智9 分钟前
企业级人员评价系统Web端重构实战:前端架构效能升级
前端·重构·架构
sunshine_程序媛10 分钟前
在Vue2项目中引入ElementUI详细步骤
前端·ui·elementui·前端框架·vue
离岸听风12 分钟前
Docker 构建文件代码说明文档
前端
VisuperviReborn17 分钟前
前端开发者的知识深度革命,从打牢基础开始
前端·javascript·架构
Nano17 分钟前
Vue响应式系统的进化:从Vue2到Vue3.X的深度解析
前端·vue.js
工业3D_大熊19 分钟前
3D Web轻量化引擎HOOPS Communicator赋能一线场景,支持本地化与动态展示?
前端·3d
某人的小眼睛23 分钟前
vue3 element-plus 大文件切片上传
前端·vue.js
东坡白菜25 分钟前
最快实现的前端灰度方案
前端