ES Modules 实战项目需兼顾模块拆分逻辑、路径管理、默认/命名导出混用、barrel module 聚合入口及浏览器与 Node.js 双环境兼容;通过 src/utils/、src/services/ 等规范目录,配合 index.html 和 type="module"、package.json 中 "type": "module" 实现原生 ESM 运行。

直接上手一个可运行、结构清晰、贴近真实开发的 ES Modules 实战项目,关键不是堆砌语法,而是把模块拆分逻辑、路径管理、默认/命名导出混用、聚合入口(barrel module)、以及浏览器和 Node.js 双环境兼容性都串起来。
一、从零搭建最小可行结构
创建如下目录,不依赖构建工具,纯原生 ESM 运行:
- src/ —— 存放所有模块代码
- src/utils/ —— 工具函数(如格式化、校验)
- src/services/ —— 数据层(模拟 API 调用)
-
src/index.js —— 应用主入口(浏览器中通过
<script type="module"></script>加载) - index.html —— 浏览器宿主页面
二、写几个典型模块并正确导出
避免“只导出不思考”。每个模块聚焦单一职责,并选择合适导出方式:
-
命名导出为主:适合工具类、常量、多个辅助函数
// src/utils/string.js<br>export const truncate = (str, len) => str.length > len ? str.slice(0, len) + '...' : str;<br>export const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1);
-
默认导出为辅:适合一个模块只暴露一个核心类或函数
// src/services/api.js<br>export default function fetchUser(id) {<br> return fetch(`/api/users/${id}`).then(r => r.json());<br>} -
混合导出示例:一个模块既有默认主功能,又附带命名工具
// src/services/auth.js<br>export const TOKEN_KEY = 'auth_token';<br>export default class AuthService {<br> static login(user) { /* ... */ }<br>}
三、用聚合模块(Barrel Module)统一出口
在 src/index.js 不直接深路径导入,而是通过中间聚合层简化引用、提升可维护性:
- 新建
src/utils/index.js:export * as string from './string.js';<br>export * as number from './number.js';<br>export { default as Validator } from './validator.js'; - 主入口
src/index.js就变得干净:import { string, number } from './utils/index.js';<br>import AuthService from './services/auth.js';<br>import fetchUser from './services/api.js';
四、双环境验证:浏览器 + Node.js
ES Modules 在两个环境运行方式不同,需分别验证:
-
浏览器中:确保
index.html的 script 标签带type="module"<script type="module" src="./src/index.js"></script> -
Node.js 中:在
package.json加"type": "module",然后执行node ./src/index.js(注意:Node.js ≥ 16 推荐) - 若需兼容 CommonJS 包(比如某些 npm 库),可用
import()动态导入,或借助createRequire桥接(仅限 Node.js)
不复杂但容易忽略。重点不在写多少模块,而在于每个 export 是否明确意图,每个 import 是否路径简洁、语义清晰。跑通这个小闭环,后续扩展路由、状态、组件库就水到渠成。











