CommonJs模块化实现原理
首先看一个案例
初始化项目
npm initnpm 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) {// 判断一下缓存中有没有当前modulevar cachedModule = __webpack_module_cache__[moduleId];if (cachedModule !== undefined) {// 缓存中有的话走缓存,返回cachedModule.exportsreturn 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)) })();