webpack4 生成的代码

初识 webpack ,先看看它打包出来的代码是怎么样的。

环境

webpack@4、 wepback-cli@3

备注:在 webpack@3 中 webpack webpack-cli 是集成在一起的,后来开发者为了方便管理和维护,对它们组成的整体进行了拆分,wepback 注重打包编译,wepback-cli 提供命令行界面接口,CLI Command line interface

配置

var path = require('path');

module.exports = {
    // webapck3 是没有 mode 这个选项的
    // webapck4+ 的 mode 默认是 'production'
    mode: 'development',
    entry: './src/single.js',
    output: {
        // 执行 webpack 命令后,打包编译生成 demo 的目录
        path: path.resolve(__dirname, 'dist'),
        // 出口文件名,和入口配置的名称对应,默认是 “main”
        filename: '[name].js'
    }
}

被打包的JS文件

// ./src/other.js
export const a = 2;
// ./src/single.js
import {a} from './other';
console.log(a);
console.log('single.js');

开发模式下生成的文件

// webpack@4 打包的代码

/**
 * 最外层是一个自执行函数,闭包了全局函数的 modules
 * 进来,这里的 modules 就是一个个的模块函数,我们
 * 编写的模块化文件最终都被映射到了 modules 上。
 */
(function (modules) { // webpackBootstrap 
  // The module cache
  /**
   * 全局安装的模块,如果模块 id 对应的模块不在全局安装
   * 的模块里,则执行这个模块函数,然后缓存到全局安装的
   * 模块里,下次需要用的时侯再从全局安装的模块里取。
   */
  var installedModules = {};

  // The require function
  // 相当于模块化规范里的 require 方法
  // 返回 module.exports 对象,即模块的导出对象。
  function __webpack_require__(moduleId) {

    // Check if module is in cache
    // 如果有对应的模块,直接返回对应的导出集合对象
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports;
    }
    // Create a new module (and put it into the cache)
    // 创建一个模块,并存入全局安装的模块里
    var module = installedModules[moduleId] = {
      i: moduleId,
      l: false,
      exports: {}
    };

    // Execute the module function
    // 执行模块 id 对应的模块函数,模块函数的执行结果都放到 module.exports 上
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

    // Flag the module as loaded
    // 标记该模块已经被加载过了,即已经执行过了模块函数
    module.l = true;

    // Return the exports of the module
    // 返回这个模块的导出对象,即 module.exports
    return module.exports;
  }

  // expose the modules object (__webpack_modules__)
  /** 将所有的模块 modules 暴露给 require 方法的 m 属性 */
  __webpack_require__.m = modules;

  // expose the module cache
  /** 将全局模块缓存 installedModules 暴露给 reqire 方法的 c 属性 */
  __webpack_require__.c = installedModules;

  // define getter function for harmony exports
  /**
   * 如果某个模块导出了相同名称的"东西",它不会被覆盖。
   * 导出对象 exports 如果没有 name 对应的属性,
   * 则为 exprots 对象 定义 name 对应的 getter,
   * 访问 exports 的 name 对应的属性时,会执行
   * getter。
   * @param {*} exports 导出的那个对象
   * @param {*} name 属性
   * @param {*} getter getter 函数
   */
  __webpack_require__.d = function (exports, name, getter) {
    // 如果导出对象 exports 没有 name 对应的属性,则为其定义 getter
    if (!__webpack_require__.o(exports, name)) {
      Object.defineProperty(exports, name, { enumerable: true, get: getter });
    }
  };

  // define __esModule on exports
  /**
   * 如果你的模块采用了 ES6+ 的模块化规范,
   * 就将 exports 导出对象标记为 ES6+ Module
   * @param {*} exports 导出的那个对象
   */
  __webpack_require__.r = function (exports) {
    // 如果支持 Symbol (ES6 的数据类型),并且 Symbol 有 toStringTag 方法
    // 则将这个 exports 对象的 toString 方法重写,exports.toString() 会输出
    // [object Module]
    if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
      Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
    }
    // 并且将 exports 的  __esModule 设为 true
    Object.defineProperty(exports, '__esModule', { value: true });
  };

  // create a fake namespace object
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  /**
   * 创建一个假的命名空间的对象,说实话真不知道用来干嘛的..
   * @param {*} value exports 或者模块 id
   * @param {*} mode 模式
   */
  __webpack_require__.t = function (value, mode) {
    // value 是模块的 id,执行 require
    if (mode & 1) value = __webpack_require__(value);
    // 直接返回 value
    if (mode & 8) return value;
    // 如果 value 已经是 ES6+ Module 的实例,直接返回 value
    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    // ns 是一个没有原型对象的空对象
    var ns = Object.create(null);
    // 将 ns 这个空对象标记为 ES6+ Module 的实例
    __webpack_require__.r(ns);
    // 为 ns 添加默认导出值 value
    Object.defineProperty(ns, 'default', { enumerable: true, value: value });
    // 如果 value 是一个对象,将它的属性浅拷贝到 ns 上,然后返回 ns
    if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
    return ns;
  };

  // getDefaultExport function for compatibility with non-harmony modules
  /**
   * 返回一个函数,获取默认导出
   * @param {*} module 整个模块
   */
  __webpack_require__.n = function (module) {
    // 如果是 ES6+ Module,则获取 module['default']
    // 不是 ES6+ Module,则获取整个的 module
    var getter = module && module.__esModule ?
      function getDefault() { return module['default']; } :
      function getModuleExports() { return module; };
    __webpack_require__.d(getter, 'a', getter);
    return getter;
  };

  // Object.prototype.hasOwnProperty.call
  /** 判断对象 object 是否有自己的 property 属性,排除继承过来的 property。 */
  __webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };

  // __webpack_public_path__
  /**
   * 应用程序中所有的资源的基本路径,和 webpack 配置里的 output.publicPath 对应,
   * 模块访问静态资源的时候会用到这个路径,它是打包编译项目后放置静态资源的目录路径
   */
  __webpack_require__.p = "";


  // Load entry module and return exports
  // 执行入口模块函数,并将导出对象返回出去
  return __webpack_require__(__webpack_require__.s = "./src/single.js");
})
/************************************************************************/
({
     "./src/other.js": (function (module, __webpack_exports__, __webpack_require__) {
        "use strict";
        eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return a; });\nconst a = 2;\n\n//# sourceURL=webpack:///./src/other.js?");

        /***/
    }),

    "./src/single.js": (function (module, __webpack_exports__, __webpack_require__) {
        "use strict";
        eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _other__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./other */ \"./src/other.js\");\n\r\nconsole.log(_other__WEBPACK_IMPORTED_MODULE_0__[\"a\"]);\r\nconsole.log('single.js');\n\n//# sourceURL=webpack:///./src/single.js?");
    })
});

总结

webpack 打包出来的 JS 文件,整体就是一个自执行函数,同时它传入了一个闭包参数——通过编译一个个的 JS 文件后生成的模块集合。

主要流程:先定义了一个“模块缓存池”(installedModules)和 webapck 自己的 require 函数(__webpack_require__),然后从入口模块函数开始执行,模块之间通过 module.exports(导出模块)和 require (导入模块)解决依赖关系,如果入口模块依赖了其他的模块,则执行该模块函数,以此类推,直到所有的依赖模块函数都被执行完。在导入模块的时候,如果这个模块不在“模块缓存池”中,则执行该模块函数,并把该函数执行后得到的模块缓存到“模块缓存池”中,下次获取该模块的时候,直接从“模块缓存池”中取,这里和 nodejs 的模块依赖机制类似。

流程图

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值