前言
在前端工程化日益庞大的今天,模块化已成为基石。从最初的"全局变量污染"到如今的"万物皆可模块",前端社区经历了漫长的探索。本文将深度解析业界主流的三大模块规范:CommonJS 、AMD 和 ES Module。
一、 CommonJS:服务端的先行者
CommonJS 是最早正式提出的 JavaScript 模块规范,伴随着 Node.js 的诞生而风靡。
1. 核心语法
- 导出 :使用
module.exports或exports。 - 导入 :使用
require。
JavaScript
// a.js
const add = (a, b) => a + b;
module.exports = { add };
// main.js
const { add } = require('./a.js');
console.log(add(1, 2));
2. 局限性与挑战
- 环境依赖:模块加载器由 Node.js 提供,高度依赖运行时环境。
- 同步阻塞 :CommonJS 规定模块加载是同步的。在服务端(磁盘读取)这没问题,但在浏览器端(网络请求),同步加载会导致 JS 解析阻塞,造成页面假死。
二、 AMD:浏览器的异步解法
为了解决 CommonJS 在浏览器端的同步阻塞问题,AMD (Asynchronous Module Definition) 应运而生。
1. 核心语法
AMD规范依赖第三方库(如RequireJS)实现,通过 define() 函数定义模块:第一个参数声明依赖模块数组,第二个参数为回调函数,依赖加载完成后执行;模块导出通过return实现。
JavaScript
// print.js 定义无依赖的模块
define(function () {
// 模块内部逻辑
function print(msg) {
console.log("print " + msg);
}
// return 导出模块成员
return {
print
};
});
// main.js 定义有依赖的模块
// 第一个参数:依赖模块列表;第二个参数:依赖加载完成后的回调
define(["./print"], function (printModule) {
// 使用依赖模块的方法
printModule.print("main");
});
2. 存在的不足
- 非原生支持 :需要引入第三方的 loader(如著名的
RequireJS)。 - 开发成本:书写格式相对复杂,代码逻辑被包裹在回调函数中,阅读和维护成本较高。
三、 ES Module (ESM):终极统一方案
ES Module(ESM) 是ECMAScript官方推出的模块化标准,也是目前现代前端工程化的唯一标准,浏览器和Node.js均已原生支持,完美解决了前两种规范的缺陷。
1. 核心语法
- 导出 :
export或export default。 - 导入 :
import。
JavaScript
// lib.js
export const version = '1.0.0';
export default function MyFunc() {}
// main.js
import MyFunc, { version } from './lib.js';
2. 为什么它是最优解?
- 编译时加载(静态分析) :ESM 在代码执行前就能确定模块依赖关系,这使得 Tree-shaking(摇树优化) 成为可能。
- 原生支持 :现代浏览器通过
<script type="module">即可直接运行,无需转换。 - 异步加载:天然支持异步,不会阻塞页面渲染。
四、 核心对比:CommonJS vs AMD vs ESM
| 维度 | CommonJS | AMD | ES Module |
|---|---|---|---|
| 加载方式 | 同步加载 | 异步加载 | 静态编译/异步加载 |
| 运行环境 | 主要用于服务端 (Node.js) | 浏览器端 (需 Loader) | 浏览器/服务端通用 |
| 典型代表 | Node.js | RequireJS | Vite, Webpack, 现代浏览器 |
五、 总结与趋势
- CommonJS 依然是 Node.js 生态的基石,但在向 ESM 过渡。
- AMD 已逐渐退出历史舞台,基本被打包工具(如 Webpack)内部处理。
- ESM 是未来,无论是前端框架(Vue3/React)还是构建工具(Vite),都在全面拥抱 ESM。