CommonJs模块化实现原理&ES Module模块化原理

CommonJs模块化实现原理

首先看一个案例
初始化项目

复制代码
npm init
npm i webpack -D

目录结构如下


webpack.config.js

复制代码
const path = require("path");
module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].js",
  },
  devtool: "source-map"
};

src/index.js

复制代码
const b = require("./b");
const a = require("./a");
console.log(a, b)

src/a.js

复制代码
let a = "这是a"
module.exports = a;

src/b.js

复制代码
let b = "这是b"
module.exports = b;

build.js

复制代码
const { webpack } = require("webpack");
const webpackOptions = require("./webpack.config.js");

const compiler = webpack(webpackOptions);

compiler.run((err, stats) => {
  console.log(err)
});

进行node ./build.js后查看dist文件下

复制代码
(() => { 
  var __webpack_modules__ = ({
    "./src/a.js": ((module) => {
        let a = "这是a"
        module.exports = a;
      }),

    "./src/b.js":
      ((module) => {
        let b = '这是b'
        module.exports = b;
      })

    });
 	// 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;
 	}
 	

     var __webpack_exports__ = {};
 	 (() => {
   		 const b = __webpack_require__("./src/b.js");
   		 const a = __webpack_require__("./src/a.js");

    	console.log(a, b);
  	 })();

 })()
;
//# sourceMappingURL=main.js.map

分析一下打包产物

首先看下 webpack_modules,我们在src/index.js中引入了a.js、b.js, webpack会把'src/a.js'、'src/b.js'作为modules的key值,该模块内容作为modules的value值;

复制代码
 var __webpack_modules__ = ({
    "./src/a.js": ((module) => {
        let a = "这是a"
        module.exports = a;
      }),

    "./src/b.js":
      ((module) => {
        let b = '这是b'
        module.exports = b;
      })

 });

定义 __webpack_require__函数

复制代码
	var __webpack_module_cache__ = {};
	function __webpack_require__(moduleId) {
		// 判断一下缓存中有没有当前module
		var cachedModule = __webpack_module_cache__[moduleId];
		if (cachedModule !== undefined) {
			// 缓存中有的话走缓存,返回cachedModule.exports
			return cachedModule.exports;
		}
		// 缓存中没有就重新创建一个moudle,设置export对象,并放入缓存
		var module = __webpack_module_cache__[moduleId] = {
			exports: {}
		};
 	
 		// 执行模块代码, 传入当前module,根据需要传入module.exports, __webpack_require__,module.exports会在模块中赋值
 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
 	
 		// 返回module.exports
 		return module.exports;
 	}

执行入口函数,为防止命名污染,封装成立即执行函数。

复制代码
 (() => {
   		 const b = __webpack_require__("./src/b.js");
   		 const a = __webpack_require__("./src/a.js");

    	console.log(a, b);
  })();

ES Module模块化原理

src/index.js

复制代码
import a from './a'
import {b} from './b'
console.log(a, b);

src/a.js

复制代码
const a = "这是a"
export default a

src/b.js

复制代码
export const b = '这是b'

node ./build.js 之后main.js如下:

复制代码
 (() => { 
 	"use strict";
 	var __webpack_modules__ = ({

    "./src/a.js":
    ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

      __webpack_require__.r(__webpack_exports__);
      __webpack_require__.d(__webpack_exports__, {
         "default": () => (__WEBPACK_DEFAULT_EXPORT__)
      });
      const a = "这是a"
      const __WEBPACK_DEFAULT_EXPORT__ = (a);
    }),

    "./src/b.js":
    ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

      __webpack_require__.r(__webpack_exports__);
      __webpack_require__.d(__webpack_exports__, {
        b: () => (b)
      });
      const b = '这是b'
    })

  });
 	
 var __webpack_module_cache__ = {};
 	
 function __webpack_require__(moduleId) {
 	var cachedModule = __webpack_module_cache__[moduleId];
 	if (cachedModule !== undefined) {
 		return cachedModule.exports;
 	}
 	var module = __webpack_module_cache__[moduleId] = {
 		exports: {}
 	};
 	__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
 		return module.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_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
 })();
 	
 (() => {
 	__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__ = {};
 (() => {
    __webpack_require__.r(__webpack_exports__);
    var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");
    var _b__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/b.js");


    console.log(_a__WEBPACK_IMPORTED_MODULE_0__["default"], _b__WEBPACK_IMPORTED_MODULE_1__.b);
  })();

})()
;
//# sourceMappingURL=main.js.map

如果是通过export default 方式导出的,那就在 exports 对象加一个 default 属性

复制代码
var __webpack_modules__ = ({

    "./src/a.js":
    ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
	// 在 ESM 模式下声明 ESM 模块标识
      __webpack_require__.r(__webpack_exports__);
      // 将模块导出的内容附加的模块对象上,如果是通过export default导出,给exports的对象加default属性
      __webpack_require__.d(__webpack_exports__, {
         "default": () => (__WEBPACK_DEFAULT_EXPORT__)
      });
      const a = "这是a"
      const __WEBPACK_DEFAULT_EXPORT__ = (a);
    }),

    "./src/b.js":
    ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

      __webpack_require__.r(__webpack_exports__);
      __webpack_require__.d(__webpack_exports__, {
        b: () => (b)
      });
      const b = '这是b'
    })

  });

通过__webpack_require__.r把模块标识为 ES Module
了解Symbol.toStringTag

复制代码
(() => {
 	__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做代理

复制代码
(() => {
 	__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))
 })();

ES Module加载CommonJS实现原理
src/index.js

复制代码
import b from './b'
console.log(b);

src/b.js

复制代码
let b = '这是b'
module.exports = b;

node ./build.js之后

复制代码
 (() => { 
 	var __webpack_modules__ = ({
    "./src/b.js": ((module) => {
      let b = '这是b'
      module.exports = b;
    })
 	});

 	var __webpack_module_cache__ = {};
 	
 	function __webpack_require__(moduleId) {
 		var cachedModule = __webpack_module_cache__[moduleId];
 		if (cachedModule !== undefined) {
 			return cachedModule.exports;
 		}
 		var module = __webpack_module_cache__[moduleId] = {
 			exports: {}
 		};
 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
 	
 		return module.exports;
 	}

 	(() => {
 		__webpack_require__.n = (module) => {
 			var getter = module && module.__esModule ?
 				() => (module['default']) :
 				() => (module);
 			__webpack_require__.d(getter, { a: getter });
 			return getter;
 		};
 	})();
 	
 	(() => {
 		__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))
 	})();
 	
 	(() => {
 		__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__ = {};
  (() => {
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    var _b__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/b.js");
    var _b__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_b__WEBPACK_IMPORTED_MODULE_0__);

    console.log((_b__WEBPACK_IMPORTED_MODULE_0___default()));
  })();

 })()
;
//# sourceMappingURL=main.js.map

由此可以看出加了这一个步骤:

通过__webpack_require__.n判断模块是否是esModule返回module

复制代码
	(() => {
 		__webpack_require__.n = (module) => {
 			var getter = module && module.__esModule ?
 				() => (module['default']) :
 				() => (module);
 			__webpack_require__.d(getter, { a: getter });
 			return getter;
 		};
 	})();

CommonJS加载ES Module的实现原理

src/index.js

复制代码
const b = require('./b.js')
console.log(b);

src/b.js

复制代码
let b = '这是b'
export default b;

node ./build.js之后

复制代码
 (() => {
 	var __webpack_modules__ = ({
    "./src/b.js": ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
      "use strict";
      __webpack_require__.r(__webpack_exports__);
      __webpack_require__.d(__webpack_exports__, {
        "default": () => (__WEBPACK_DEFAULT_EXPORT__)
      });
      let b = '这是b'
      const __WEBPACK_DEFAULT_EXPORT__ = (b);
    })

 	});

 	var __webpack_module_cache__ = {};
 	
 	function __webpack_require__(moduleId) {
 		var cachedModule = __webpack_module_cache__[moduleId];
 		if (cachedModule !== undefined) {
 			return cachedModule.exports;
 		}
 		var module = __webpack_module_cache__[moduleId] = {
 			exports: {}
 		};
 	
 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
 	
 		return module.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_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
 	})();
 	
 	(() => {
 		__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__ = {};
    (() => {

    const b = __webpack_require__(/*! ./b.js */ "./src/b.js")
    console.log(b);
  })();

 })()
;
//# sourceMappingURL=main.js.map
相关推荐
iCxhust26 分钟前
在 emu8086 中可以直接编译运行的完整汇编程序,演示数组的定义、遍历、求和、求最大值。
开发语言·前端·javascript·汇编·单片机·嵌入式硬件·算法
JianZhen✓30 分钟前
2026前端高频面试题总结(Vue/JS/网络/Webpack/性能优化/手写)
前端·javascript·vue.js
星光开发者1 小时前
基于springboot电动汽车租赁管理系统-计算机毕设 附源码 11217
javascript·spring boot·mysql·django·php·html5·express
李白的天不白1 小时前
webpack 与 vue-loader 版本冲突问题
前端·vue.js·webpack
空中海1 小时前
05 React Native架构设计、主线项目与专家实践
javascript·react native·react.js
kyriewen12 小时前
代码写成一锅粥?3个设计模式让你的项目“起死回生”
前端·javascript·设计模式
不会敲代码112 小时前
从零搭建 AI 日记助手:用 Milvus 向量数据库实现语义搜索
javascript·openai
threelab14 小时前
Three.js UV 图像变换效果 | 三维可视化 / AI 提示词
javascript·人工智能·uv
竹林81815 小时前
用Viem替代ethers.js:从一次签名失败到完整迁移的实战记录
前端·javascript
不可能的是16 小时前
Claude Code 子 Agent 机制全解:怎么跑起来、怎么被管理、怎么互不干扰
javascript