我们先设计一个例子

  1. /** ./src/index.js **/
  2. import { name, age } from './title';
  3. console.log(name);
  4. console.log(age);
  1. /** ./src/title.js **/
  2. module.exports = {
  3. name: 'title_name',
  4. age: 'title_age'
  5. }

主要代码

ESModule 加载 commonjs 会比前几个复杂一点。主要是多了一个 n 方法。
我们先把相同的部分拿过来

  1. (() => {
  2. var modules = ({
  3. "./src/title.js":
  4. ((module) => {
  5. module.exports = {
  6. name: 'title_name',
  7. age: 'title_age'
  8. }
  9. })
  10. });
  11. var cache = {};
  12. function require(moduleId) {
  13. var cachedModule = cache[moduleId];
  14. if (cachedModule !== undefined) {
  15. return cachedModule.exports;
  16. }
  17. var module = cache[moduleId] = {
  18. exports: {}
  19. };
  20. modules[moduleId](module, module.exports, require);
  21. return module.exports;
  22. }
  23. require.n = (module) => {
  24. //n 方法函数体
  25. //.....
  26. };
  27. require.d = (exports, definition) => {
  28. for (var key in definition) {
  29. Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  30. }
  31. };
  32. require.r = (exports) => {
  33. Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  34. Object.defineProperty(exports, '__esModule', { value: true });
  35. };
  36. var exports = {};
  37. (()=>{
  38. // 说明当前 index.js 模块是一个 commonjs 模块
  39. require.r(exports);
  40. var title = require("./src/title.js");
  41. // 调用 n 方法
  42. var title_default = require.n(title);
  43. console.log(title_default().name);
  44. console.log(title.age);
  45. })()
  46. })();

require.n 方法

n 方法接收一个入参,就是导出对象,会判断导出对象是 commonjs 还是 esModule:

  • 如果是 esModule 就返回模块对象上的 default 属性。
  • 否则就返回导出对象。
  • 因为从之前的打包逻辑看:
    • 如果引入的是 ESModule,打包后的 commonjs 会将 ESModule 的默认导出赋值到导出对象 exports 的 default 属性上。
    • 反之是直接返回导出对象 exports 上的属性。
      1. //....
      2. require.n = (module) => {
      3. var getter = module.__esModule ?
      4. () => module['default'] :
      5. () => module;
      6. // 这一行代码在我们这个例子中没有用到 这个a属性只会在一种非常特殊的情况下用到
      7. require.d(getter, { a: getter });
      8. return getter;
      9. };
      10. //....

      最终代码

      ```javascript (() => { var modules = ({ “./src/title.js”: ((module) => { module.exports = {
      1. name: 'title_name',
      2. age: 'title_age'
      } }) }); var cache = {}; function require(moduleId) { var cachedModule = cache[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } var module = cache[moduleId] = { exports: {} }; modulesmoduleId; return module.exports; } require.n = (module) => { var getter = module.esModule ? () => module[‘default’] : () => module; // 这一行代码在我们这个例子中没有用到 这个a属性只会在一种非常特殊的情况下用到 require.d(getter, { a: getter }); return getter; }; require.d = (exports, definition) => { for (var key in definition) { Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); } }; require.r = (exports) => { Object.defineProperty(exports, Symbol.toStringTag, { value: ‘Module’ }); Object.defineProperty(exports, ‘esModule’, { value: true }); }; var exports = {}; (() => { // 说明当前 index.js 模块是一个 commonjs 模块 require.r(exports); var title = require(“./src/title.js”);
// 因为在这里我不知道这个 './src/title.js' 模块是 commonjs 还是 esmodule
// 想要取得默认导出,需要加个判断
// 相当于
// let title = title.__esModule ? title.default : title
var title_default = require.n(title);


console.log(title_default().name);
console.log(title.age);

})() })();

下面是打印结构<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1584826/1657769775103-3abcdf1c-5bbc-445d-9a4d-d00e380ea68c.png#clientId=ub7fd12a9-7507-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=514&id=u8adf202a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1028&originWidth=1120&originalType=binary&ratio=1&rotation=0&showTitle=false&size=197754&status=done&style=none&taskId=ue34c0ffc-1832-473c-ac09-58a70d9fcd2&title=&width=560)
<a name="KmDAL"></a>
## webpack 打包源码
然后我们再看一下源码对比一下,相差不大。
```javascript
/******/ (() => { // webpackBootstrap
/******/     var __webpack_modules__ = ({

/***/ "./src/title.js":
/*!**********************!*\
  !*** ./src/title.js ***!
  \**********************/
/***/ ((module) => {

  module.exports = {
    name: 'title_name',
    age: 'title_age'
  }

  /***/ })

  /******/     });
  /************************************************************************/
  /******/     // The module cache
  /******/     var __webpack_module_cache__ = {};
  /******/     
  /******/     // The require function
  /******/     function __webpack_require__(moduleId) {
  /******/         // Check if module is in cache
  /******/         var cachedModule = __webpack_module_cache__[moduleId];
  /******/         if (cachedModule !== undefined) {
  /******/             return cachedModule.exports;
  /******/         }
  /******/         // Create a new module (and put it into the cache)
  /******/         var module = __webpack_module_cache__[moduleId] = {
  /******/             // no module.id needed
  /******/             // no module.loaded needed
  /******/             exports: {}
  /******/         };
  /******/     
  /******/         // Execute the module function
  /******/         __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  /******/     
  /******/         // Return the exports of the module
  /******/         return module.exports;
  /******/     }
  /******/     
  /************************************************************************/
  /******/     /* webpack/runtime/compat get default export */
  /******/     (() => {
  /******/         // getDefaultExport function for compatibility with non-harmony modules
  /******/         __webpack_require__.n = (module) => {
  /******/             var getter = module && module.__esModule ?
  /******/                 () => (module['default']) :
  /******/                 () => (module);
  /******/             __webpack_require__.d(getter, { a: getter });
  /******/             return getter;
  /******/         };
  /******/     })();
  /******/     
  /******/     /* 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 });
  /******/         };
  /******/     })();
  /******/     
  /************************************************************************/
  var __webpack_exports__ = {};
  // This entry need to be wrapped in an IIFE because it need to be in strict mode.
  (() => {
  "use strict";
  /*!**********************!*\
    !*** ./src/index.js ***!
    \**********************/
  __webpack_require__.r(__webpack_exports__);
  /* harmony import */ var _title__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./title */ "./src/title.js");
  /* harmony import */ var _title__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_title__WEBPACK_IMPORTED_MODULE_0__);

  console.log(_title__WEBPACK_IMPORTED_MODULE_0__.name);
  console.log(_title__WEBPACK_IMPORTED_MODULE_0__.age);
  })();

  /******/ })()
  ;