ES6 Module

70 阅读2分钟

export

  • 声明导出

    export const name = "fiona"; // let var function function* class
    
  • 命名导出:

    export { name };
    export { name as nameCopy };
    
  • 默认导出:

    export default "fiona";
    export { name as default };
    
  • 重定向导出:

    export * from "module"; // 导出 module 中除 default 以外的内容
    export { name } from "module";
    export { name as nameCopy } from "module";
    

    这种方式导出的内容不可在本模块使用

import

  • 命名导入:

    import { name } from "module";
    import { name as nameCopy } from "module";
    import * as module from "module"; // 导出 module 的所有内容,包括 default。
    
  • 默认导入:

    import module from "module";
    import { default as module } from "module"; // 吃饱了撑的
    
  • 仅执行:

    import "module";
    
  • 函数式导入:

    import("module")
    
    • 类似 CommonJS 中的 require
    • 返回一个 Promise 对象,resolve 的值为 module 的所有内容,包括 default。

Webpack 下的实现原理分析

  • 例子:

    • b.js

      export const name = "moduleB";
      
    • a.js

      export { name as nameCopy } from "./b.js";
      export default "moduleA";
      export const age = 18;
      
    • index.js

      import a, { nameCopy, age as ageCopy } from "./a.js";
      console.log(a); // moduleA
      console.log(nameCopy); // moduleB
      console.log(ageCopy); // 18
      
  • 打包后的源码分析:

    (() => {
      "use strict";
      // 所有子模块集合,key 为路径,值为包含了模块代码的函数。
      var __webpack_modules__ = {
        "./src/a.js": (
          __unused_webpack_module,
          __webpack_exports__,
          __webpack_require__
        ) => {
          // 为 module.exports 添加模块标识
          __webpack_require__.r(__webpack_exports__);
          // 将导出内容添加至 module.exports 上
          __webpack_require__.d(__webpack_exports__, {
            // 声明导出就是为了确保有一个变量名用于接收,如果直接导出一个变量则无法给它命名,也就无法导入。
            age: () => age,
            // 默认导出以 __WEBPACK_DEFAULT_EXPORT__ 命名,所以导出时无需声明。
            default: () => __WEBPACK_DEFAULT_EXPORT__,
            // 重命名导出的其实还是原模块的值
            nameCopy: () => _b_js__WEBPACK_IMPORTED_MODULE_0__.name,
          });
          var _b_js__WEBPACK_IMPORTED_MODULE_0__ =
            __webpack_require__("./src/b.js");
    
          const __WEBPACK_DEFAULT_EXPORT__ = "moduleA";
          var age = 18;
        },
    
        "./src/b.js": (
          __unused_webpack_module,
          __webpack_exports__,
          __webpack_require__
        ) => {
          __webpack_require__.r(__webpack_exports__);
          __webpack_require__.d(__webpack_exports__, {
            name: () => name,
          });
          var name = "moduleB";
        },
      };
    
      // 模块缓存
      var __webpack_module_cache__ = {};
    
      // 加载模块的函数
      function __webpack_require__(moduleId) {
        // 查看是否有缓存,若有则直接返回,不再重复执行。
        var cachedModule = __webpack_module_cache__[moduleId];
        if (cachedModule !== undefined) {
          return cachedModule.exports;
        }
        // 若没有缓存,则首先创建新的 module 对象并添加至缓存。
        var module = (__webpack_module_cache__[moduleId] = {
          exports: {},
        });
    
        // 找到对应模块并执行,将新建的 module 对象、module.exports、以及加载模块的函数作为参数传入。
        __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
    
        // 返回 module.exports
        return module.exports;
      }
    
      (() => {
        // 将模块导出的内容绑定到模块的 exports 上,且设置为只读(writable 默认为 false)。
        __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_require__.o = (obj, prop) =>
          Object.prototype.hasOwnProperty.call(obj, prop);
      })();
    
      (() => {
        // 给每个模块对象的 exports 加一个标识
        __webpack_require__.r = (exports) => {
          if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
            // 修改 toString 的结果
            Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
          }
          // 添加一个 __esModule 属性,值为 true。
          Object.defineProperty(exports, "__esModule", { value: true });
        };
      })();
    
      // 入口模块
      var __webpack_exports__ = {};
      (() => {
        // 1. 首先给入口模块添加 Module 标识
        __webpack_require__.r(__webpack_exports__);
        // 2. 导入 a.js
        var _a_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");
    
        console.log(_a_js__WEBPACK_IMPORTED_MODULE_0__["default"]);
        console.log(_a_js__WEBPACK_IMPORTED_MODULE_0__.nameCopy);
        console.log(_a_js__WEBPACK_IMPORTED_MODULE_0__.age);
      })();
    })();
    

References