【导入模式】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"
    }
  }
}
相关推荐
倔强青铜三10 分钟前
WXT浏览器插件开发中文教程(5)----WXT配置详解之浏览器启动设置
前端·javascript·vue.js
倔强青铜三21 分钟前
WXT浏览器插件开发中文教程(4)----WXT配置详解之manifest清单
前端·javascript·vue.js
若初&1 小时前
【新手初学】读取数据库数据
前端·数据库·web安全
靠近彗星1 小时前
Django:构建高性能Web应用
前端·python·django·sqlite
顺凡2 小时前
深入剖析 Browser Use:49.9K+ Star 的 AI 驱动浏览器自动化框架
前端·aigc·测试
沐土Arvin2 小时前
深入 SVG:矢量图形、滤镜与动态交互开发指南
开发语言·前端·javascript·css·html
IT、木易2 小时前
如何利用 CSS 的clip - path属性创建不规则形状的元素,应用场景有哪些?
前端·css
2501_906800762 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·数学建模·web
海盗强3 小时前
vue子组件生命周期的执行顺序
前端·javascript·vue.js