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...

相关推荐
周淳APP1 分钟前
【React Hook全家桶】大致过一遍React Hooks
前端·javascript·react.js·前端框架·react hooks
sheji34163 分钟前
【开题答辩全过程】以 基于web的图书借阅系统的设计与实现为例,包含答辩的问题和答案
前端
CodeSheep9 分钟前
两位大佬相继离世,AI时代我们活得太着急了
前端·后端·程序员
xuankuxiaoyao10 分钟前
VUE.JS 实践 第三章
前端·javascript·vue.js
放下华子我只抽RuiKe523 分钟前
NLP自然语言处理硬核实战笔记
前端·人工智能·机器学习·自然语言处理·开源·集成学习·easyui
PieroPc23 分钟前
电脑DIY组装报价系统 用MiMo V2 Pro 写html ,再用opencode(选MiMo 作模型) 当录入口
前端·html
工程师老罗26 分钟前
lvgl有哪些布局?
前端·javascript·html
好家伙VCC28 分钟前
# 发散创新:用Selenium实现自动化测试的智能断言与异常处理策略在现代Web应用开发中,*
java·前端·python·selenium
关中老四40 分钟前
【原生JS甘特图MZGantt 】如何给父任务设置独立进度条
前端·javascript·甘特图
英俊潇洒美少年43 分钟前
react 18 的fiber算法
前端·算法·react.js