ESM(ECMAScript Modules)前端开发介绍与使用指南
一、什么是 ESM?
ECMAScript Modules(ESM) 是 JavaScript 语言官方标准化的模块系统,自 ECMAScript 2015(ES6) 起正式引入,并在后续版本中不断完善。作为现代 Web 开发的基石,ESM 解决了长期以来 JavaScript 缺乏原生模块化支持的问题。
模块化历史演进
| 阶段 |
方案 |
特点 |
| 早期 |
全局变量模式 |
功能挂载到全局对象,易冲突 |
| 中期 |
CommonJS |
Node.js 使用,同步加载 |
| 中期 |
AMD/UMD |
浏览器异步加载,配置复杂 |
| 现代 |
ESM |
原生标准,静态分析,树摇优化 |
二、ESM 核心语法
1. 导出(Export)
// 命名导出
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
// 默认导出(每个模块只能有一个)
export default function main() {
console.log('默认导出');
}
// 批量导出
export { PI, add, main };
// 重命名导出
export { PI as MathPI };
2. 导入(Import)
// 导入默认导出
import main from './module.js';
// 导入命名导出
import { PI, add } from './module.js';
// 导入全部
import * as utils from './module.js';
// 重命名导入
import { PI as CirclePI } from './module.js';
// 动态导入(按需加载)
const module = await import('./module.js');
3. ES2025 新特性:JSON 模块支持
// 无需 fetch + JSON.parse,直接导入
import configData from './config-data.json' with { type: 'json' };
// 静态导入
import packageInfo from './package.json' assert { type: 'json' };
三、前端项目中使用 ESM
1. HTML 中直接使用
<!DOCTYPE html>
<html>
<head>
<title>ESM 示例</title>
</head>
<body>
<!-- 使用 type="module" -->
<script type="module" src="./main.js"></script>
<!-- 内联模块 -->
<script type="module">
import { add } from './utils.js';
console.log(add(1, 2));
</script>
</body>
</html>
2. 构建工具配置
Vite(推荐,原生 ESM 支持)
// vite.config.js
export default {
// Vite 默认使用 ESM,无需额外配置
optimizeDeps: {
esbuildOptions: {
target: 'es2020'
}
}
}
Webpack
// webpack.config.js
module.exports = {
experiments: {
outputModule: true // 启用 ESM 输出
},
output: {
module: true,
chunkFormat: 'module'
}
}
package.json 配置
{
"type": "module", // 启用 ESM
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
}
}
四、ESM vs CommonJS 对比
| 特性 |
ESM |
CommonJS |
| 语法 |
import/export |
require/module.exports |
| 加载方式 |
静态分析,编译时加载 |
动态加载,运行时加载 |
| 执行时机 |
模块加载时执行 |
调用时执行 |
| 绑定方式 |
活绑定(引用) |
值拷贝 |
| 树摇优化 |
✅ 支持 |
❌ 不支持 |
| 浏览器支持 |
✅ 原生支持 |
❌ 需转换 |
| 异步加载 |
✅ import() |
❌ 需额外处理 |
五、最佳实践
1. 模块组织
src/
├── index.js # 入口文件
├── components/ # 组件模块
├── utils/ # 工具函数
├── services/ # API 服务
└── styles/ # 样式文件
2. 代码分割与懒加载
// 路由级代码分割
const Home = () => import('./pages/Home.vue');
const About = () => import('./pages/About.vue');
// 条件加载
if (condition) {
const module = await import('./heavy-module.js');
module.init();
}
3. 避免循环依赖
// ❌ 不良实践:循环引用
// a.js
import { b } from './b.js';
// b.js
import { a } from './a.js';
// ✅ 解决方案:提取公共模块
// common.js
export const shared = {};
// a.js & b.js 都从 common.js 导入
4. 纯 ESM 包发布(2025 趋势)
根据 Vue/Vite 核心团队成员 Anthony Fu 的建议,2025 年推荐发布纯 ESM 包:
{
"type": "module",
"exports": {
".": "./dist/index.js"
},
"engines": {
"node": ">=18.0.0"
}
}
六、兼容性处理
1. 浏览器支持
| 浏览器 |
最低支持版本 |
| Chrome |
61+ |
| Firefox |
60+ |
| Safari |
10.1+ |
| Edge |
16+ |
2. 降级方案
<!-- 模块脚本 -->
<script type="module" src="./app.js"></script>
<!-- 降级脚本(不支持 module 的浏览器) -->
<script nomodule src="./app-legacy.js"></script>
3. Babel 转换配置
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
targets: {
browsers: ['>0.25%', 'not dead']
},
modules: false // 保留 ESM 语法
}]
]
}
七、ES2025 ESM 新特性
| 特性 |
说明 |
状态 |
| JSON 模块导入 |
原生支持 .json 文件导入 |
✅ 已发布 |
| Import Attributes |
with { type: 'json' } 语法 |
✅ 已发布 |
| 延迟模块评估 |
优化模块加载性能 |
✅ 已发布 |
| 动态 import() 增强 |
更好的错误处理 |
✅ 已发布 |
// ES2025 JSON 模块示例
import config from './config.json' with { type: 'json' };
console.log(config.apiKey);
// 错误处理
try {
const module = await import('./optional-module.js');
} catch (error) {
console.error('模块加载失败:', error);
}
八、常见问题与解决方案
1. CORS 错误
// 确保服务器设置正确的 CORS 头
// Access-Control-Allow-Origin: *
2. 路径问题
// ✅ 使用完整路径(带扩展名)
import { util } from './utils/util.js';
// ❌ 避免省略扩展名
import { util } from './utils/util';
3. Node.js 中使用 ESM
// package.json
{
"type": "module"
}
// 或使用 .mjs 扩展名
// app.mjs
import fs from 'fs';
九、总结
| 优势 |
说明 |
| 🎯 标准化 |
官方规范,跨平台统一 |
| 🚀 性能优化 |
静态分析支持树摇 |
| 📦 代码组织 |
清晰的依赖关系 |
| 🔒 安全性 |
严格模式,作用域隔离 |
| 🌐 浏览器原生 |
无需额外工具即可使用 |
2026 年建议:
- ✅ 新项目直接使用 ESM
- ✅ 构建工具优先选择 Vite
- ✅ 发布 npm 包推荐纯 ESM
- ⚠️ 老项目逐步迁移,注意兼容性
ESM 已成为现代前端开发的标准配置,掌握 ESM 是前端开发者的必备技能!