前端模块化规范
CommonJS、AMD、CMD、UMD、ESM 的区别与使用
问题
前端有哪些模块化规范?它们的区别是什么?
解答
CommonJS
Node.js 采用的规范,同步加载模块。
// math.js - 导出模块
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
module.exports = { add, subtract };
// 或者
exports.add = add;
exports.subtract = subtract;
// main.js - 导入模块
const math = require('./math.js');
console.log(math.add(1, 2)); // 3
// 解构导入
const { add } = require('./math.js');
特点:
- 同步加载,适合服务端
- 运行时加载,可以动态 require
- 导出的是值的拷贝
AMD (Asynchronous Module Definition)
异步模块定义,RequireJS 实现,适合浏览器。
// 定义模块 math.js
define('math', [], function() {
return {
add: function(a, b) { return a + b; },
subtract: function(a, b) { return a - b; }
};
});
// 定义有依赖的模块
define('calculator', ['math'], function(math) {
return {
calculate: function(a, b) {
return math.add(a, b);
}
};
});
// 使用模块
require(['calculator'], function(calculator) {
console.log(calculator.calculate(1, 2)); // 3
});
特点:
- 异步加载,不阻塞页面
- 依赖前置,提前执行
CMD (Common Module Definition)
SeaJS 实现,与 AMD 类似但依赖就近、延迟执行。
// 定义模块
define(function(require, exports, module) {
// 依赖就近,用到时再 require
var math = require('./math');
exports.calculate = function(a, b) {
return math.add(a, b);
};
});
// 异步加载
define(function(require, exports) {
require.async('./math', function(math) {
console.log(math.add(1, 2));
});
});
特点:
- 依赖就近,延迟执行
- 用到时才加载依赖
UMD (Universal Module Definition)
兼容 CommonJS、AMD 和全局变量的通用方案。
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['dependency'], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS
module.exports = factory(require('dependency'));
} else {
// 浏览器全局变量
root.MyModule = factory(root.Dependency);
}
})(typeof self !== 'undefined' ? self : this, function(dependency) {
// 模块代码
return {
add: function(a, b) { return a + b; }
};
});
特点:
- 兼容多种环境
- 常用于打包库文件
ESM (ES Modules)
ES6 原生模块规范,现代浏览器和 Node.js 都支持。
// math.js - 命名导出
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// 默认导出
export default function multiply(a, b) {
return a * b;
}
// main.js - 导入
import multiply, { add, subtract } from './math.js';
import * as math from './math.js';
console.log(add(1, 2)); // 3
console.log(multiply(2, 3)); // 6
console.log(math.subtract(5, 2)); // 3
// 动态导入
const module = await import('./math.js');
// HTML 中使用
// <script type="module" src="main.js"></script>
特点:
- 静态分析,编译时确定依赖
- 导出的是值的引用(绑定)
- 支持 Tree Shaking
对比表格
| 规范 | 加载方式 | 运行环境 | 依赖处理 |
|---|---|---|---|
| CommonJS | 同步 | Node.js | 运行时加载 |
| AMD | 异步 | 浏览器 | 依赖前置 |
| CMD | 异步 | 浏览器 | 依赖就近 |
| UMD | - | 通用 | 兼容多种 |
| ESM | 异步 | 通用 | 静态分析 |
关键点
- CommonJS 同步加载,导出值的拷贝,适合 Node.js
- AMD 异步加载、依赖前置,RequireJS 实现
- CMD 异步加载、依赖就近,SeaJS 实现
- UMD 兼容方案,用于发布通用库
- ESM 是标准规范,静态分析,支持 Tree Shaking,导出值的引用
目录