2026-01-26

7 阅读6分钟

记录每天自我学习转前端的碎碎念,仅作加强记忆的笔记和自我监督打卡使用。

CMD(Common Module Definition)

是一种用于浏览器端 JavaScript 的模块化规范,具有以下核心特性

1.‌按需加载‌

CMD 采用懒加载机制,只有在需要时才加载依赖模块,显著优化性能。例如:

define(function(require) {
// 需要时再加载依赖
const increment = require('./increment');

increment.add(1);

});

2.‌依赖就近‌

与 AMD 的依赖前置不同,CMD 允许在代码中就近声明依赖,提高可维护性:

define(function(require, exports) {
// 模块逻辑...
const utils = require('./utils'); // 依赖在调用处声明

exports.result = utils.calculate();

});

‌实现方式‌

通过全局函数 define(factory) 定义模块,其中 factory 支持函数/对象/字符串形式:

// 函数形式(主流)

define(function(require, exports, module) {
  module.exports = { ... };
});

// 对象/字符串形式
define({ data: 'value' }); // 直接导出对象

‌执行机制‌

模块定义后‌不会立即执行‌,仅在调用时执行,减少资源占用。

‌代表库与定位‌ 由国内开发者玉伯提出,SeaJS 是其典型实现,专为解决浏览器异步模块加载设计,兼容 CommonJS 规范。

AMD(Asynchronous Module Definition)

是一种‌异步模块定义规范‌,专为解决浏览器端 JavaScript 模块化开发而设计,核心特性如下

1.‌异步加载‌

模块按需异步加载,避免阻塞页面渲染和脚本执行。

require(['moduleA', 'moduleB'], function(A, B) {
// 依赖加载完成后执行
});

2.依赖前置

在模块定义时‌显式声明所有依赖‌,依赖加载完毕后才执行回调函数:

define(['dep1', 'dep2'], function(dep1, dep2) {
  return {}; // 模块接口
});

3.标准 API‌

define(id?, deps?, factory)‌:定义模块(id 为模块名,deps 为依赖数组,factory 为工厂函数)。

‌require(deps, callback)‌:动态加载模块

与 CMD 规范的区别‌

特性‌AMD (RequireJS)CMD (SeaJS)
依赖声明‌前置声明(模块头部定义)就近声明(代码中按需加载)
执行时机‌依赖加载后立即执行延迟到 require 时执行
代表库‌RequireJSSeaJS

适用场景‌

  1. ‌浏览器环境‌
  2. 解决传统脚本同步加载的阻塞问题,尤其适合大型 Web 应用。
  3. ‌复杂依赖管理‌
  4. 明确声明依赖关系,提升代码可维护性。
  5. ‌历史项目兼容‌
  6. 支持旧版浏览器模块化开发。

局限性‌

  1. ‌代码冗余‌:依赖前置语法增加代码量。
  2. ‌服务器支持弱‌:主要针对浏览器设计,Node.js 环境不适用。
  3. ‌已逐渐被替代‌:ES6 模块(import/export)成为现代开发主流。

典型实现‌:RequireJS 是 AMD 最广泛使用的库,通过 define.amd 属性标识兼容性。

关于使用webpack打包,umd规范

UMD规范可以同时兼容AMDCommonJs规范,下面代码是通过webpack打包且设置umd格式,设置mode为development得到的代码,改模式下代码没有压缩

(function webpackUniversalModuleDefinition(root, factory) {
  if (typeof exports === 'object' && typeof module === 'object') {
  // CommonJS模块环境(如Node.js),
  // 在 Vue 项目中将上述 UMD 格式的库作为 npm 依赖使用时,‌会进入这个分支,
  // 原因解析:Vue CLI 或 Webpack 构建的项目在 Node.js 环境中执行模块加载,该环境同时存在 exports   和 module 对象,满足第一个分支的条件
  // 当通过 import 或 require 引入 npm 包时,Node.js 的 CommonJS 模块系统会自动激活,触发       module.exports 导出逻辑
// 当执行 import 语句时,底层会调用 CommonJS 的 require() 函数加载模块。该函数执行目标模块的代码,并返回其 module.exports 对象的值
   module.exports = factory();
}
  else if (typeof define === 'function' && define.amd) {
// 此分支检测AMD模块环境(如RequireJS)
   define([], factory);
  }
  else if (typeof exports === 'object') {
// 此分支用于兼容仅存在exports对象的环境(例如某些CommonJS环境,但不完全符合Node.js规范)
   exports["weixin"] = factory();
  }
  else {
   // 当以上条件都不满足时,说明处于非模块化环境(如浏览器全局作用域)
   root["weixin"] = factory();
  }
  })(self, () => {
  return (() => {
  "use strict";
  var __webpack_modules__ = {
  "./src/weixin.js": ((__unused_webpack_module, __webpack_exports__,  __webpack_require__) => {
  eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */   __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"age\": () => (/*   binding */ age),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ \"name\": () => (/* binding */ name)\n/* harmony export */ });\nconst name = \"li\";\nconst age = 18;\nconst height = 180;\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (height);\n\n\n//# sourceURL=webpack://weixin/./src/weixin.js?");
  })
  };
  var __webpack_require__ = {};
  /*
  // 立即执行函数写法1-箭头函数
  (() => {

  })();

  // 立即执行函数写法2-普通函数
  (function (){

  })()
**/
  (() => {
  __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_modules__["./src/weixin.js"](0, __webpack_exports__, __webpack_require__);
/*
此时的__webpack_exports的值是
  {
   age: 18,
   default: 180,
   name: "li",
   __esModule: true,
   Symbol(Symbol.toStringTag): "Module"
  }
*/
  // 如果配置了libraryExport: 'default',则多了下面这行代码,不配置就没有这行代码
  __webpack_exports__ = __webpack_exports__["default"];
  // 上面代码执行后,__webpack_exports的值变成了180
  return __webpack_exports__;
  })();
});
/*

在此demo中,__webpack_exports__最终的值为
{
age: 18,
default: 180,
name: "li",
__esModule: true,
Symbol(Symbol.toStringTag): "Module"
}

如果在webpack的配置中设置了
output:{
  libraryExport: 'default',
}
则在处理返回数据前加上 __webpack_exports__ = __webpack_exports__["default"];
这行代码会重新赋值__webpack_exports__,只取了里面的default值
__webpack_exports__变成了180
这样在使用时是无法访问具名导出的name和age,只能访问默认导出的变量
这里需要注意,使用默认导出时,得到的直接是导出变量的值,没有key

不配置libraryExport: 'default'时,得到的数据是
{
age: 18,
default: 180,
name: "li",
__esModule: true,
Symbol(Symbol.toStringTag): "Module"
}
为什么这里的height键变成了default?
因为webpack在执行__webpack_require__.d = (exports, definition) => {})函数,这个函数会遍历definition的key给
__webpack_exports__赋值,传入的definition里就是固定的key:default,这个default的值取的就是export.default的值
所以生成的 __webpack_exports__会包含default,没有export.default的那个key:height
**/

Webpack 配置中的 librarylibraryTarget 是用于控制库(library)打包方式的核心参数,其作用和配置规则如下:

libraryTarget 的作用‌

决定库的‌导出形式‌,支持多种模块规范: 1.var‌(默认值)

var MyLibrary = ... // 作为全局变量暴露this / window / global

挂载到指定全局对象(浏览器中 window.MyLibrary,Node.js 中 global.MyLibrary)。

2.commonjs / commonjs2‌

commonjs:导出为 exports["MyLibrary"]
commonjs2:导出为 module.exportsNode.js 标准)

‌3.amd‌

// 通过 AMD 规范定义模块(需配合 RequireJS):
define("MyLibrary", [], factory);

‌3.umd‌(推荐)

通用模块定义,自动兼容 CommonJS、AMD 和全局变量环境。

library 的作用‌

指定库的‌全局变量名或模块名‌

1.当 libraryTarget 为 var/this/window 时:

output: {
 library: "MyLib", // 生成 window.MyLib
 libraryTarget: "var"
}

2.当 libraryTarget 为 umd 时:

output: {
 library: "MyLib", // 浏览器: window.MyLib | Node.js: require('MyLib')
 libraryTarget: "umd"
}

3.当 libraryTarget 为 amd 时:

output: {
 library: "MyAMDModule", // define("MyAMDModule", ...)
 libraryTarget: "amd"
}