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

相关推荐
mldong2 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排2 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60613 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角4 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!4 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰4 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi6 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen6 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马7 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒7 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端