Derived Modular Arch
概念

Shared

可移植代码:ui、lib、api、model、domain 分组及成长规则。

shared/ 是项目中 按代码种类分组 唯一说得通的地方。这里没有 feature 或产品流程——只有可放进任意应用的横向能力。

shared/ 里的一切 默认公开。不需要 public/ 文件夹——这一层就是为了被导入。

分组

shared/
├── ui/       # UI primitives — no product knowledge
├── lib/      # pure helpers, infrastructure wrappers
├── api/      # transport: base client, interceptors
├── model/    # infra state: query client, env, flags
└── domain/   # shared business types (optional)
分组放什么不要放什么
ui/按钮、输入框、layout 原语、图标了解订单/购物车的组件
lib/日期、格式化、i18n、storage只有一个模块需要的 helper
api/基础 HTTP/WS client、auth 管道某个 feature 的 endpoint
model/Query client、路由常量、env/configFeature 业务状态
domain/UserMoney、branded ID只属于一个模块的类型

shared 内部方向

各组稳定性与导入权限不同:

domain → (nothing)
lib    → domain
api    → lib, domain
model  → api, lib, domain
ui     → lib, domain     (✗ api, ✗ model)

ui 不能拉网络或全局产品状态——否则就不再是可移植原语。

lib vs api vs feature api

三个不同位置——常见混淆点:

代码位置原因
基于 fetchget<T>()shared/api/http.ts传输层,不知 endpoint
fetchCatalogProducts()features/catalog/catalog.api.ts单个 feature 的 endpoint;其他模块不导入
formatCurrency()shared/lib/format-currency.ts纯 helper,非网络

第二个模块调用同一 产品 API(非传输层)——提升到 services/,不是 shared/api

示例见 vite-react example

与模块 segment 的区别

名字相同(uimodelapi),但 规则不同

  • features/checkout/ui 可以 导入 features/checkout/model
  • shared/ui 不能 导入 shared/model

模块是孤岛,有自己的内部规则。shared 是公共层,可移植性要求严格。

代码如何进入 shared

Second-use 规则(第二次使用规则): 不要「为未来」抽取。helper 移到 shared/两个及以上模块 导入它。信号——dma doctor 中的 shared-candidate

例外:从第一天就引导基础设施(基础 API client、env、首批 UI 原语),如果整个应用都用它们。

反向路径

如果 shared/ 里某文件 只有 一个消费者——移回模块内部。Colocation 比过早 shared 更便宜。这是 review 决策;尚无专用 doctor 规则。

组内成长

像模块一样,组也在原地变密:

shared/ui/button.tsx  →  shared/ui/button/  (when many files accumulate)

uiapi 是 shared 里最不稳定的居民;package 提取(stage 4)的首批候选。

shared vs services 边界

Shared——可移植代码。Services——有模块入边的产品流程。拿不准——Services vs Shared

工具检查什么

规则抓什么
layer-direction从 shared「向上」导入
shared-candidate (doctor)被 2+ 模块导入的文件——该考虑 lift

下一步

On this page