【导入模式】AMD & ESM & CJS & UMD区别

突然有点模糊了,故浅总结下这几个导入模式的区别😂

一、核心特性对比表

特性 CommonJS (CJS) AMD ESM (ES Modules) UMD
加载方式 同步 (Node.js) 异步 (浏览器优先) 静态/动态 (原生支持) 环境自适应
语法 require/module.exports define/require import/export IIFE 包裹多种环境判断
作用域 模块作用域 函数作用域 模块作用域 全局变量或模块作用域
适用环境 Node.js 服务端 浏览器 (RequireJS) 现代浏览器/Node.js 14+ 跨环境兼容
Tree-Shaking 困难 困难 原生支持 困难
典型应用 npm 包开发 旧浏览器项目 现代前端框架 通用库开发

二、CommonJS (CJS)

ini 复制代码
javascript
// 导出
module.exports = { key: 'value' };
exports.fn = () => {};

// 导入
const lib = require('./lib');
const { fn } = require('./utils');

技术原理

  • 设计于 2009 年,Node.js 默认模块系统
  • 同步加载导致浏览器端性能问题
  • 模块缓存机制 (require.cache)

现代应用

  • 仍主导 Node.js 生态 (85%+ npm 包使用 CJS)
  • 需配合 @babel/plugin-transform-modules-commonjs 转换 ESM

三、AMD (Asynchronous Module Definition)

javascript 复制代码
javascript
// 定义模块
define('moduleId', ['dep1', 'dep2'], (d1, d2) => {
  return { method: () => d1.action() };
});

// 加载模块
require(['module'], (mod) => mod.method());

技术原理

  • RequireJS 实现的浏览器优先方案
  • 依赖前置声明 + 异步加载
  • 适合网络环境差的旧浏览器场景

现代替代

  • 逐步被 <script type="module"> 原生 ESM 替代
  • Webpack 等工具可输出 AMD 格式供旧系统使用

四、ESM (ECMAScript Modules)

javascript 复制代码
javascript
// 导出
export const name = 'ESM';
export default function() {};

// 导入
import { name } from './module.js';
import lib from './lib.js';

核心优势

  1. 静态结构:编译时确定依赖关系,支持 Tree-Shaking
  2. 浏览器原生支持:无需打包工具直接运行 (Chrome 61+ / Firefox 60+)
  3. 循环引用处理:通过实时绑定 (Live Binding) 安全处理
  4. 动态导入import() 实现代码分割

Node.js 集成

json 复制代码
json
// package.json
{
  "type": "module",  // 启用 ESM
  "exports": {
    ".": {
      "import": "./esm/index.js",  // ESM 入口
      "require": "./cjs/index.cjs" // CJS 回退
    }
  }
}

五、UMD (Universal Module Definition)

javascript 复制代码
javascript
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['dep'], factory);
  } else if (typeof exports === 'object') {
    // CJS
    module.exports = factory(require('dep'));
  } else {
    // 全局
    root.MyLib = factory(root.Dep);
  }
})(this, (dep) => {
  // 模块逻辑
  return { /* ... */ };
});

设计哲学

  • 兼容层模式:一套代码适配 AMD/CJS/全局变量
  • 文件体积通常比单环境格式大 30%+ (含环境检测代码)

现代应用场景

  • 需通过 <script> 标签直接引入的公共库 (如图表库)
  • 微前端架构中的跨技术栈模块共享

六、模块转换关系图

graph LR A(CJS) -->|Babel/ESBuild| D(ESM) B(AMD) -->|Webpack| D D -->|Rollup| C(UMD) C -->|Tree-Shaking| D

七、工具链支持对比

工具 CJS 支持 AMD 支持 ESM 支持 UMD 支持
Webpack ✅ 原生 ✅ 插件 ✅ 5.0+ 原生 ✅ 配置输出格式
Rollup ✅ 插件 ✅ 插件 ✅ 原生 ✅ 配置输出格式
Vite ✅ 预构建转换 ❌ 需插件 ✅ 原生 ✅ 构建输出选项
ESBuild ✅ 自动转换 ✅ 原生 ✅ 格式选项

八、选型建议指南

  1. 新项目开发

    • 前端项目 → 原生 ESM + Vite
    • Node.js 服务 → 混合 ESM/CJS (逐步迁移)
  2. 库开发

    • 公共库 → UMD + ESM 双格式发布
    • 私有库 → ESM 单格式
  3. 遗留系统维护

    • 浏览器端 → AMD → 用 Webpack 转换为 ESM
    • Node.js → CJS → 增量迁移为 ESM
  4. 性能关键型

    • 浏览器端 → ESM 原生加载 + HTTP/2
    • 服务端 → CJS (同步加载无性能瓶颈)

九、代码示例:现代库的多格式发布

项目结构

perl 复制代码
dist/
  ├── my-lib.umd.js     # UMD 格式
  ├── my-lib.esm.js     # ESM 格式
  └── my-lib.cjs.js     # CJS 格式

package.json 配置

json 复制代码
json
{
  "name": "my-lib",
  "main": "dist/my-lib.cjs.js",
  "module": "dist/my-lib.esm.js",
  "browser": "dist/my-lib.umd.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.esm.js",
      "require": "./dist/my-lib.cjs.js"
    }
  }
}
相关推荐
崔庆才丨静觅17 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606118 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了18 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅18 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅18 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅19 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment19 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅19 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊19 小时前
jwt介绍
前端
爱敲代码的小鱼19 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax