JavaScript项目依赖分层的核心目标是职责清晰、影响可控、构建调试可预测;核心模块零外部依赖,适配层隔离环境与第三方库,应用层按能力域组织依赖流,构建需反映分层意图。

JavaScript 项目中依赖分层的核心目标是:让模块职责清晰、变更影响可控、构建与调试更可预测。关键不在于“分几层”,而在于“谁依赖谁、为什么这么依赖”。
核心模块应零外部依赖(除语言原生)
所谓核心模块,指业务逻辑主干、领域模型、纯工具函数等不涉及环境或副作用的代码。它们必须:
- 不引入任何 npm 包(包括 lodash、date-fns 等通用库)
- 不调用浏览器 API(如 localStorage、fetch)、Node.js API(如 fs、path)或框架 API(如 React.useState)
- 所有输入通过参数传入,所有副作用通过返回值或回调显式表达
例如一个订单金额计算函数:✅ 正确 —— 接收 price、discount、taxRate 三个数字,返回 number;❌ 错误 —— 内部读取 localStorage 中的用户等级再算折扣。
适配层(Adapter)隔离环境与第三方库
真实世界的能力(HTTP 请求、时间获取、加密、UI 渲染)必须收口到明确的适配模块中,例如:
立即学习“Java免费学习笔记(深入)”;
-
apiClient.ts封装 axios/fetch 调用,只暴露getOrder(id)这类业务语义方法 -
clock.ts提供now()和parse(dateStr),内部用 Date 构造但可被测试替换成固定时间 -
storage.ts抽象 get/set/clear,底层可切换 localStorage / IndexedDB / mock
这些模块可依赖第三方库,但绝不向核心模块暴露第三方类型或错误对象(如不抛出 AxiosError,而是转为自定义 OrderFetchError)。
应用层按能力域组织依赖流
页面、组件、服务等运行时模块属于应用层,它可依赖:
- 核心模块(直接 import)
- 适配模块(直接 import)
- 框架/UI 库(如 React、Vue、Ant Design)
但禁止跨域依赖:例如「用户管理页」不能直接 import 「支付 SDK 的 sign 方法」,而应通过「支付适配器」提供 signPayment(payload)。这种约束靠目录结构 + ESLint 规则(如 import/no-restricted-paths)强制。
构建与打包需反映分层意图
分层不是开发习惯,要落实到产出物:
- 核心模块单独发布为
@org/core包,无 dependencies 字段(仅 peerDependencies 声明对 TypeScript 版本的要求) - 适配模块打包为
@org/adapters,dependencies 包含 axios、crypto-js 等,但 exports 只暴露抽象接口 - 应用层不发布为包,其 node_modules 中的第三方库不得被核心模块 require 到
可通过 rollup-plugin-node-resolve 的 preferBuiltins: false 和 browser: true 配合检查,确保核心模块未意外解析到非原生模块。










