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

相关推荐
陈随易1 小时前
农村程序员-关于小孩教育的思考
前端·后端·程序员
云深时现月1 小时前
jenkins使用cli发行uni-app到h5
前端·uni-app·jenkins
昨天今天明天好多天1 小时前
【Node.js]
前端·node.js
2401_857610031 小时前
深入探索React合成事件(SyntheticEvent):跨浏览器的事件处理利器
前端·javascript·react.js
雾散声声慢2 小时前
前端开发中怎么把链接转为二维码并展示?
前端
熊的猫2 小时前
DOM 规范 — MutationObserver 接口
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
天农学子2 小时前
Easyui ComboBox 数据加载完成之后过滤数据
前端·javascript·easyui
mez_Blog2 小时前
Vue之插槽(slot)
前端·javascript·vue.js·前端框架·插槽
爱睡D小猪2 小时前
vue文本高亮处理
前端·javascript·vue.js
开心工作室_kaic2 小时前
ssm102“魅力”繁峙宣传网站的设计与实现+vue(论文+源码)_kaic
前端·javascript·vue.js