es modules 是 spa 中模块统一管理的基础设施,需按领域组织目录、通过契约接口跨域调用、统一导出入口、分离状态与逻辑,并用 eslint 工程化约束边界。

在大型单页应用(SPA)中,ES Modules 不只是语法糖,而是模块统一管理的基础设施。关键不在“用不用 import”,而在于如何用它建立可预测、可追溯、可收敛的模块组织体系。
按领域划分模块目录,禁止跨层直连
把模块按业务域而非技术类型组织,例如 features/user/、features/order/、shared/api/、shared/utils/。每个域内封装完整能力,对外只暴露明确接口。
- 禁止组件直接导入另一个功能域的 hook 或 service,比如
order/CheckoutForm不该import { fetchUserProfile } from '../user/api' - 跨域调用必须经由
shared/contracts/下的契约接口,如import { UserContext } from 'shared/contracts/user-context' - 所有入口文件(如路由组件、页面组件)只依赖本域模块 + shared 契约,形成清晰的依赖边界
统一导出入口,收敛模块引用路径
每个功能域设一个 index.ts(或 .js),集中 re-export 对外可用的内容,避免外部代码深挖子路径。
- 例如
features/user/index.ts写:export { default as UserProfileCard } from './components/UserProfileCard'; export { useUserQuery } from './hooks/useUserQuery'; - 其他模块统一导入
features/user,而不是features/user/hooks/useUserQuery - 配合 TypeScript 的
paths别名(如"@user": ["src/features/user"]),进一步简化和标准化引用
状态与逻辑分离:模块不自带运行时状态
ES Modules 是静态结构,但模块内部若维护可变状态(如缓存对象、计时器、未清理的监听器),就会导致模块复用失效、测试困难、内存泄漏。
- 工具函数模块(如
shared/utils)保持纯函数,无闭包捕获、无副作用 - 数据获取模块(如
shared/api)只导出配置化函数,如createApiClient(baseURL),不自行实例化 client - 状态相关逻辑(如用户登录态、购物车)交由上层框架机制管理(React Query、Pinia、Zustand),模块本身不 hold 实例
构建时约束:用 ESLint + import/no-restricted-paths 拦截违规引用
仅靠约定不够,需工程化手段守住模块边界。在 ESLint 中配置规则,阻止高风险路径访问。
- 禁止页面模块直接读取
src/main.ts或src/env.ts—— 环境变量应通过shared/config统一注入 - 禁止
features/**模块导入node_modules中非白名单库(如禁止直接用lodash,改用shared/utils封装的精简版) - 对第三方 SDK(如支付、埋点)做薄封装层(
integrations/alipay/),主业务模块只能导入封装后接口
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











