Skip to main content

JavaScript模块化规范(ESM、UMD、CMD、AMD)

JavaScript模块化规范(ESM、UMD、CMD、AMD)的出现是为了解决代码复用、命名冲突及依赖管理等问题。简单来说,AMD和CMD是面向浏览器环境的“旧时代”方案,CommonJS是Node.js的同步加载方案,UMD是一个兼容各方的“万金油”方案,而ESM是现代JavaScript的官方标准。

下面是这四种规范的详细对比:

规范/格式核心特点主要适用环境加载方式核心语法
ESM官方标准,现代浏览器的原生方案现代浏览器、现代Node.js (v12+)异步import / export
UMD通用模块定义,兼容多种环境需要兼容各种环境的通用库依环境而定通过检测环境使用对应语法
CMD通用模块定义,推崇依赖就近,延迟执行浏览器环境 (依赖Sea.js)异步define(function(require, exports, module) {...})
AMD异步模块定义,推崇依赖前置浏览器环境 (依赖RequireJS)异步define(['dep1', 'dep2'], function(dep1, dep2) {...})

🔍 细节差异

  • ESM (ECMAScript Modules):作为ECMAScript 2015 (ES6) 引入的官方模块系统,它是静态加载的,可以在编译时确定模块依赖关系,有利于**Tree Shaking(移除无用代码)**等优化。模块通过export导出,通过import导入。
  • UMD (Universal Module Definition):它本身不是一种独立的模块规范,而是一种兼容模式。它通过运行时判断,将模块分别以CommonJS、AMD或全局变量的方式暴露出去,实现了“Write once, run anywhere”的目标。
  • CMD (Common Module Definition):以国内的Sea.js为代表,与AMD的主要区别在于模块加载的时机:
    • CMD依赖就近,懒执行。你可以在代码的任何位置require一个模块,模块只有在真正被require时才会执行。
    • AMD依赖前置,依赖项会提前执行。你在定义模块时就需要声明所有依赖,且依赖模块会被立刻执行,这在大型应用中可能影响首屏性能。
  • 关于执行时机的说明:虽然AMD的模块在定义时会提前执行,但这并不意味着模块的代码被阻塞了,因为AMD本身就是异步加载的,不会阻塞页面渲染。

💎 如何选择?

  • 新项目:首选 ESM 对于新项目,ESM 是绝对的首选。它语法简洁,支持现代优化,并且是浏览器和Node.js原生支持的官方标准,代表着未来。
  • 库/工具开发:考虑 UMD 如果你在开发一个需要发布到npm、供其他开发者使用的库,UMD是个好选择,能保证项目在各种环境中(无论是支持ESM的现代项目,还是依赖AMD的旧项目)都能被正确加载。
  • 旧项目维护:AMD/CMD 只有在维护基于 RequireJS (AMD) 或 Sea.js (CMD) 的旧项目时,才需要深入学习这两种规范。