@domain-first/project-structure

中文文档
8.8.0发布于 2026/11/12MITTypeScriptESM + CJS构建来源已验证近 30 天下载 6840

用 CLI 构建和管理您的域- 第一项目结构

中文使用文档
文档目录24 节
  1. 这是什么?
  2. API 密码
  3. 指南
  4. 代理工具的非交互模式
  5. 如何初始化项目
  6. 节省的执行类型
  7. 如何创建有界限的上下文
  8. 如何添加总和
  9. 如何添加使用大小写、命令或查询
  10. 如何切换执行
  11. 如何连接依赖关系
  12. 如何添加执行内容
  13. 如何移动或重命名模块
  14. 如何删除模块
  15. 如何添加错误
  16. 如何在上下文之间共享代码
  17. 如何添加 REST 端点
  18. 脚手架反应模块
  19. 如何添加工具
  20. 如何检查规则
  21. 如何看待结构
  22. 如何升级为新的主要版本
  23. 如何教你的编码代理
  24. 许可证

域 第一个项目结构

version TypeScript ready semver license

少花时间设置文件 。 花更多的时间建立你的域名.

这是什么?

在大多数TypeScript代码库中,您在方便和架构之间选择. 围绕域的清晰边界和角色意味着更多的文件,更多的合同和更多的接线,因此在最后期限的压力下,逻辑在最快速写出的地方就结束. 边界模糊了一条捷径.

域首工程结构去除此选择 : 最干净的道路也是最短的交互式的 CLI 询问新代码的上下文、上层和作用是什么,并用尊重边界的合同、执行、测试骨架和接线来代替它。 只有在抚养规则允许的情况下,才提供抚养权。 做正确的事情需要一些提示;做错误的事情需要额外的努力。 它知道这个 @domain-first 包:类型、出错、处理器、接线和处理器。 生成的文件属于您的工程; 您会写商业规则 .

npm i -D @domain-first/project-structure
npx df-init
npx df-scaffold

API 密码

整个技术规格存在于 API.md (英语)。 。 。 .

指南

代理工具的非交互模式

df-scaffold, (中文(简体) ), df-react 财务报告和审定财务报表 df-integration 接受JSON的请求。 人类可以继续使用交互式菜单. 特工可以先发现计划 和项目ID:

npx df-scaffold --describe
npx df-scaffold --request '{"operation":"query","context":"sales","name":"orders","implementation":{"type":"prisma","save":false},"dependencies":{"PrismaOrdersQuery":["shared-kernel:PrismaInfrastructureService"]}}'
npx df-react --request '{"operation":"widget","name":"admin/orders","widgetType":"separated"}'
npx df-integration --request '{"operation":"add","integrations":["storybook"]}'

--request - 从Stdin读JSON. dryRun: true 不写入预览更改; overwrite: true 明确允许替换已更改的现有生成文件。 答复是JSON,有档案清单、下一步和诊断。 错误返回 ok: false 和非零退出代码而不返回到提示;无效的请求丢弃阶段更改 。 初始化通过 df-init。 。 。 .

这个 API 参考 描述请求字段、发现ID和结果语义.

如何初始化项目

运行 df-init 在项目中 package.json. 安排访问 项目-后端-前端 以顺序。 每个段落询问是否现在配置它: 回答否然后配置它 。 跳过工程保存源文件夹 src; 跳过后端或前端时,该部分不在此列.

npx df-init
# Return to one section later:
npx df-init --section backend
npx df-init --section frontend

工程要求源文件夹 。 后端请求 @domain-first 软件包 envBranchedWire 分支 与 wire,共享内存 DB 和测试库,然后添加所需的共享克内尔文件. 与 @domain-first/handlers-rest,它会添加 端点生成器前端报价 反应 或者说 下一个.js然后是"故事书" 启用故事本运行现有的 React + Vite 集成: 它创建 .storybook 配置、软件包脚本和构建输出 .gitignore 输入。 选择配置后端的 Next.js 询问 对 REST 端点使用 @ domain- first/ handlers- next 一次 一次吗 添加为 " 是 " handlers-rest 连接到后端软件包 nextAdapter 并创造出全程路线。 这以前是可行的 next 已安装。 随着后端被推迟,REST的设置等待到后端配置. 丢失的软件包被打印为安装命令;没有自动安装.

所有设置和保存的执行类型都生活在 domain-first.project-structure.config.json数字 :

{
    "project": { "rootFolder": "src" },
    "backend": {
        "domainFirstPackages": ["@domain-first/wire", "@domain-first/handlers"],
        "withInMemoryDb": true,
        "testingLibrary": "vitest",
        "implementations": {
            "repositories": { "primary": ["prisma", "mongo"], "test": ["stub"] },
            "commands": { "primary": ["sql"], "test": [] },
            "queries": { "primary": ["elastic"], "test": ["fake"] },
            "ports": { "primary": ["s3"], "test": [] }
        },
        "rules": {
            "dependencies": {
                "domain-services": ["domain-services"],
                "repositories": ["domain-services", "application-ports", "infrastructure-services"],
                "application-ports": ["repositories", "domain-services", "application-ports", "infrastructure-services"],
                "application-services": ["repositories", "domain-services", "application-ports", "commands", "queries"],
                "use-cases": ["repositories", "domain-services", "application-ports", "application-services", "commands", "queries"],
                "commands": ["infrastructure-services"],
                "queries": ["infrastructure-services"],
                "infrastructure-services": ["repositories", "domain-services", "application-ports", "infrastructure-services"],
                "presentation-services": ["application-ports", "application-services", "use-cases", "commands", "queries", "presentation-services"]
            },
            "lint": {
                "context-isolation": true,
                "shared-kernel": true,
                "layers": true,
                "dependencies": true,
                "react": true,
                "clock": true,
                "config": true
            }
        }
    },
    "frontend": {
        "react": { "framework": "react", "storybookFramework": "@storybook/react-vite" }
    }
}

将配置交给你的团队 重运行 df-init 提议 项目, (中文(简体) ), 后端, (中文(简体) ), 前端 财务报告和审定财务报表 所有款次,以当前值作为默认值。 单节更新保存了其他部分并保存了选择. 后端设置将所有标准依赖性列表写入并启用 backend.rules,因此可以直接编辑。 在重新配置时,只填写缺失的规则;现有名单, add编号 :remove 补丁和已停用的检查被保留. 后端设置保存了现有的支持文件并恢复了缺失的文件. 更改源文件夹会影响未来的生成;现有源不会被移动. 反应通过存在 frontend.react; 其编号 framework 实值 react 或者说 next,所以Next.js使用相同的反应发电机. 前端选择从所保存的值预填入, 返回 Next.js 当 next 已声明为 package.json两种选择 @storybook/react-vite 从"故事书"集成;没有单独的"故事书"框架提示. 框架设置仍按 frontend.<framework>。 。 。 .

先前主要版本的配置不读:命令停止并请求您运行 df-upgrade。缺失后端或反应部分生成一条指向相应消息 df-init --section 命令。 初始化和配置由项目所有者进行;代理技能只读取这些设置并请求所有者配置缺失的段落.

节省的执行类型

仓库、命令、查询和端口生成器提供执行类型的菜单. 输入执行类型并保存供未来使用 接受一个新的 kebab 大小写名称并将其保存在 backend.implementations 在共享配置中. 只输入此运行的执行类型 生成代码而不添加保存的选择。 这两项行动都适用于初级和测试实施,包括增加现有合同.

每个类别及其主要/测试选择是分开的,由项目的所有背景共同选择。 普通类型,例如: api 财务报告和审定财务报表 mock 非预设: 手动输入或保存到以后。 菜单包含被保存的选择,可用的系统执行和两个人工输入动作.

系统实施有明确标记:

  • 系统: 交叉语句( 在另一个限定语境中的调用处理器) —— 端口适配器,只有在另一个有界限上下文存在时才使用.
  • 系统:内存(使用共享的内存数据库) ——寄存器,命令和查询,只有当共享的内存 DB 集成被启用,其文件已经准备好.

第一个可用的保存类型是默认选择的,然后是可用的系统类型;否则将选择保存条目动作,其名称输入为空. 在现有合同中添加一项执行,既显示主要选择,也显示测试选择。 通过保存动作,普通类型会按照其选定的环境被记住;只运行的动作从不注册.

更新至 backend.implementations 保存所有其他配置区域,并与生成的文件一起保存;取消同时丢弃。 Prisma 合并增加 prisma 到寄存器、命令和查询选择。 没有全球持续违约设置.

如何创建有界限的上下文

选择 脚手架新上下文 并输入名称, 如 sales。它开始为空:在第一个错误之前没有错误命名空间.

对每个名字使用小写 kebab 大小写 : place-order 变成 PlaceOrderUseCase。 。 。 .

如何添加总和

选择 范围:销售 / 领域 / 新的总量名称 order,并添加一个带有 prisma 执行情况和实施情况 in-memory 测试一.

src/bounded-contexts/sales/
├── domain/aggregates/order/
│   ├── index.ts
│   ├── order.aggregate-root.ts
│   └── order-repository.ts
├── infrastructure/repositories/
│   ├── prisma/prisma-order-repository.ts
│   └── in-memory/in-memory-order-repository.ts
└── wiring/repositories/wire-order-repository.ts

实体和价值对象进入一个集合(新实体, (中文(简体) ), 新建值对象)或进入上下文 domain/。 。 。 .

如何添加使用大小写、命令或查询

选择 应用程序 – 新使用大小写, (中文(简体) ), 新命令 或者说 新建查询与 @domain-first/handlers班级有计划占位符和一个 handle 与 defineHandler。 。 。 .

export class PlaceOrderUseCase {
    constructor() {}

    static inputSchema = {};
    static outputSchema = {};

    handle = defineHandler({
        inputSchema: PlaceOrderUseCase.inputSchema,
        outputSchema: PlaceOrderUseCase.outputSchema,
        handler: async (input) => {
            return {};
        },
    });
}

命令或查询在 application/ 执行情况 infrastructure/就像一个仓库 查询只读取数据,绝不更改数据;任何更改都是命令.

如何切换执行

与 @domain-first/wire,存储器、命令、查询和端口每个执行一个工厂,由 NODE_ENV数字 :

export const wireOrderRepository = envBranchedWire({
    test: wireInMemoryImplementation,
    development: wirePrismaImplementation,
    production: wirePrismaImplementation,
});

测试得到测试的执行,其他的都得到初级.

您的环境可能不同: 选择 自定义分支 在后端设置时输入, 例如 . local, staging, production,然后选择测试分支,让我们 df-init 添加 test,或者不设一个:然后每个分支得到初级执行,不需要测试执行。 生成的电线使用这些树枝. 如何选择当前分支 : env-branched-wire.ts 获得空 currentBranch 函数,直到您写入它才编译.

如何连接依赖关系

作为最后一步,装有电线的发电机提供新单元可能依赖的模块,这些模块来自相同的界限上下文和共享核心。 跨文本端口适配器也参见相邻上下文的应用程序处理器. 工厂和建筑厂都增加了每个选择:

export class PlaceOrderUseCase {
    constructor(private readonly orderRepository: OrderRepository) {}
}

export const wirePlaceOrderUseCase = wireClass(PlaceOrderUseCase, [
    wireOrderRepository,
]);

只提供了尊重地层的依赖性:一个用例不能取另一个用例,域不能取应用程序. 以后要添加依赖,请选择 电线依赖 在上下文菜单中。 有十个以上选择的菜单,如模块列表,取一个搜索:将名称的一部分打入过滤.

如何添加执行内容

选择 基础设施 + 新执行 以给一个现有的寄存器、命令、查询或端口一个额外的执行,比如 local a 的适配器 FileStorage 旁边的端口 s3 财务报告和审定财务报表 in-memory与 wire,选择使用它的环境: test 继续 in-memory, (中文(简体) ), development 移动到 local, (中文(简体) ), production 继续 s3。 。 。 .

如何移动或重命名模块

选择 移动或重命名 在上下文菜单中:重命名一个集合、实体、值对象、服务、端口、查询、命令或使用大小写,将其移动到另一个有边框的上下文或共享克内尔上下,或将一个实体在集合中或外移动。 其文件、执行、电线、规格以及项目中的每个导入和衍生名称都随之而来: OrderRepository, (中文(简体) ), PrismaOrderRepository, (中文(简体) ), wireOrderRepository,则 orderRepository 参数,一个使用大小写,内嵌 DB 部分。 将禁止进口引入上下文之间的举动,连同将跨越边界的进口清单被拒绝.

如何删除模块

选择 删除 在上下文菜单中选择模块。 其所有档案包括:合同、执行、电线和规格、一个装有整个文件夹的集合,加上其他地方为其添加的线条生成器(一个实体的再出口总量,一个集合的内膜DB部分)。 虽然另一个文件仍然导入它,但没有任何内容被删除,CLI列出了这些导入,因此没有留下任何破损.

如何添加错误

选择 域 – 出错 在上下文命名空间中添加错误,创建嵌入式命名空间,或者添加出错。 上下文命名空间( E)SalesErrors = errorNamespace('sales') 内 domain/errors/index.ts)是在没有命名空间的情况下添加第一个错误后创建的.

export class OutOfStock extends SalesErrors.define('out-of-stock') {}

名称不重复上下文:错误 payment 名称空间 sales 实值 PaymentDeclined在共享核心中,它们以 SharedKernelError数字 : TimeoutSharedKernelError。 。 。 .

如何在上下文之间共享代码

将每个上下文的域和应用模型保持本地化. 对于另一个上下文的数据或行为,创建 应用程序端口 b. 消费背景下的应用程序 + 新端口选择 系统: 交叉语句( 在另一个限定语境中的调用处理器) 为它的适配器。 不需要运输或终点.

端口适配器菜单包含已保存的端口类型和手动输入动作,加 系统: 交叉语句( 在另一个限定语境中的调用处理器) 当另一个受约束的上下文存在时。 没有自动 api, (中文(简体) ), mock 或者说 in-memory 端口选择。 已保存的主端口和测试端口类型仍然分开;添加另一个适配器可以显示两个列表. 从寄存器、命令和查询中的选择不添加到端口菜单中.

与 wire, (中文(简体) ), 交叉连接的依赖性.. 财务报告和审定财务报表 电线依赖 提供查询、命令和使用来自每个相邻上下文、带有上下文标记的大小写,例如: InvoiceQuery (billing). CLI将每个操作器注入适配器并用接线导入工厂. 名称包括避免相撞的上下文: BillingInvoiceQuery, (中文(简体) ), wireBillingInvoiceQuery。 。 。 .

定义您端口中的能力方法并在适配器中执行:绘制您的输入图,调用被注入的处理器,并将其结果和出错映射到您自己的模型. 分开 mock 或者说 stub 测试适配器, 因此测试不会运行相邻上下文 。 无 wire将操作器通过构造器注入,然后自己编成接线.

仅在下端口适配器 infrastructure/application-adapters/cross-context/ 可能导入邻居的处理器。 电线只能将它们注入那些适配器;查询/命令执行和其他适配器类型仍然孤立. 这个 cross-context 类型无法用于共享内核端口。 共享的普遍模式、技术港口和服务属于 共享核心 (单位:千美元)src/shared-kernel) (中文(简体) ).

如何添加 REST 端点

与 @domain-first/handlers-rest选择 演示文稿 → 新处理器- REST 端点,选择或创建控制器、方法和相对路径。 A. 背景情况 sales控制器 orders路径 recent 财务报告和审定财务报表 get 给:

src/bounded-contexts/sales/presentation/rest/orders/recent/GET.ts   // GET /sales/orders/recent

对于上下文本身,选择上下文根控制器 (根)-/社会-网络它生活在 presentation/rest/(root)/,不包含路径的文件夹:空路径和 get 给 GET /social-networks 内 src/bounded-contexts/social-networks/presentation/rest/(root)/GET.ts (单位:千美元)SocialNetworksGetEndpoint),路径 :id 给 GET /social-networks/:id路径 from-scratch 与 post 给 POST /social-networks/from-scratch。一个路线属于一个控制器,所以 (root)/from-scratch 和控制器 from-scratch 相互排斥。 以8.5为背景端点的项目 npx df-upgrade。 。 。 .

每个端点都使用项目的一个端点生成器, RestEndpointGeneratorPresentationService 内 src/shared-kernel/presentation/services/初始化脚手架,作为常规的共享克内尔演示服务(类,谱和线):

/**
 * The adapter of your HTTP framework.
 */
const adapter = undefined as unknown as Adapter<any[], any>

export class RestEndpointGeneratorPresentationService {
    get withoutGuards(): EndpointGenerator {
        return createEndpoint({
            errors: [invalidRequest()]
        })(adapter) as EndpointGenerator
    }
}

设置模块级别 adapter 常数高于您的 HTTP 框架的适配器; 类通过关闭使用。 如果您连接了下一个适配器, 文件导入 nextAdapter 从 @domain-first/handlers-next 相反,没有设置,和 app/api/[...path]/route.ts (单位:千美元)src/app/… 当文件夹存在时)服务端点 nextEndpoints。通过接线,线路服务 restHandlers,所以每一个新的终点都工作而不碰它;在第一个终点之前,路线是不编译的,CLI也这么说. 每个生成方法都是返回的取出器 EndpointGenerator: 每个终点增加一个(例如) withAuth,带有 context 和错误绘图。 保留 invalidRequest() 联 合 国 @domain-first/handlers-rest 无效请求( e)400)并添加自己的绘图: errors: [httpError(MyError, 404), invalidRequest()]。一个新的终点呼叫 this.endpointGenerator(...) 并且不是故意编译的: 选择自己在它的 get handle(),比如说. this.endpointGenerator.withoutGuards(...)。 。 。 .

通过接线,端点将生成器和从上下文的询问中选择的处理器,命令和使用大小写,所有端点被收集为 restHandlers 内 src/presentation/rest/index.ts连接到您的 HTTP 服务器 .

脚手架反应模块

与 frontend.react 配置, 运行 npx df-react: pages,部件(monolithic,有分离的UI,或无头),有故事本故事的UI-kit组件,以及共享的钩子. 名称可包括文件夹:

admin/panel/users  →  pages/admin/panel/admin-panel-users-page.tsx  (AdminPanelUsersPage)

随着Next.js,一个新页面也得到了它的App路由器路线, app/admin/panel/users/page.tsx,它使得 AdminPanelUsersPage。现有路径永远不会被覆盖.

移动或重命名页面 财务报告和审定财务报表 移动或重命名部件 移动文件并更新项目中的每个导入. 删除页面 财务报告和审定财务报表 删除部件 一旦没有导入它们, 删除它们, 如果您同意的话, 将包含 Next.js 页面的路径 。 UI-kit组件和共享钩可以移动,更名并同样删除. 随着Next.js,移动一页 也提出移动它的路线, app/admin/users/ → app/backoffice/users/,因为它的URL随它而改变.

如何添加工具

运行 npx df-integration 来配置一个或几个 REST 端点生成器、 共享的相模 DB、 故事本、 Prisma 8、 Vitest、 Playwright 、 在 Testcontainers 、 OpenAPI 生成器或 Orval API 客户端( 类型客户端和 React 查询钩头) 上的集成测试。 集成添加配置文件、软件包脚本和 .gitignore 条目,然后打印一个安装命令复制。 没有为你安装或运行.

端点生成器和内膜DB是什么 df-init 脚手架;作为集成,它们会在后期添加或还原缺失的文件,并且永远不覆盖已存在的文件.

使用Testcontainers, CLI 询问哪些执行类型获得集成测试(prisma 对, stripe 也许不是。 从那时起,每一次新的执行这种类型,比如: PrismaOrdersQuery中,获取一个字符 specs/integration/ 它通过它的电线 并运行对 PostgreSQL 在容器; 基础设施服务 当你问。 单位规格与域名模式,服务及用例一致.

如何检查规则

npx df-lint

它报告了违反域-第一规则的情况:禁止在有界上下文之间进口、禁止从地层进口、使用依赖性规则不允许的模块(在进口和接线中)、进口它们不应进口的模块、阅读没有时钟和配置端口的时间或环境变量。 当发现某物时,它与1一起退出,这样你就可以在CI中运行.

df-init 脚手架上所有标准规则 backend.rules 在后端设置中。 团队可以直接编辑这些条目:每种模块可能取决于什么(backend.rules.dependencies)和哪些检查运行(backend.rules.lint) (中文(简体) ). df-scaffold 根据同样的规则提供依赖性。 对于较旧或手动缩短的配置 backend.rules,默认值和每一次检查运行;类型和检查您不提及保留其默认值.

  • 进来吧 backend.rules.dependencies (作为钥匙和列表): repositories, (中文(简体) ), domain-services, (中文(简体) ), application-ports, (中文(简体) ), application-services, (中文(简体) ), use-cases, (中文(简体) ), commands, (中文(简体) ), queries, (中文(简体) ), infrastructure-services, (中文(简体) ), presentation-services。 。 。 .
  • 类型值: 替换默认值的列表, 或 { "add": [...], "remove": [...] }。 。 。 .
  • 报到 backend.rules.lint数字 : context-isolation, (中文(简体) ), shared-kernel, (中文(简体) ), layers, (中文(简体) ), dependencies, (中文(简体) ), react, (中文(简体) ), clock, (中文(简体) ), config。 。 。 .

默认和细节 : 扶养规则, (中文(简体) ), df-lint。 。 。 .

{
    "backend": {
        "rules": {
            "dependencies": {
                "use-cases": {
                    "add": [
                        "use-cases"
                    ]
                }
            },
            "lint": {
                "clock": false
            }
        }
    }
}

如何看待结构

npx df-graph                    # bounded contexts and the Shared Kernel
npx df-graph --context sales    # the modules of one context by layer
npx df-graph --html                 # open the rendered charts in the browser
npx df-graph --out docs/ARCHITECTURE.md

df-graph 读取线条并绘制人鱼图:哪些上下文通过跨文本端口互相联系,这些上下文使用共享克内尔,在上下文中,每个模块都依赖于什么. 它会打印图表,打开已渲染的一页 --html (美人鱼来自CDN),或写作 --out 以扩展格式: .md 对于GitHub, 它使图表, .mmd, (中文(简体) ), .json 或者说 .html。 。 。 . --json 给工具和代理人同样的图表.

如何升级为新的主要版本

在将软件包升级为新的主要版本后, 运行 :

npx df-upgrade --dry-run   # review the plan
npx df-upgrade

它发现项目需要什么,显示每个变化,并在一次确认后一起应用; --yes 跳过问题。 在此之前,其他命令, df-lint 包含, 请停止 run npx df-upgrade再次运行它打印 Everything is up to date.

从 7.x 将配置拆分为 project, (中文(简体) ), backend 财务报告和审定财务报表 frontend,记录 frontend.react.framework 明确(next 何时 next 进入 package.json,否则 react)和移动 defaultPersistenceLayerImplementation 到第一个保存的主类型寄存器、命令和查询。 然后更新代理技能 npx df-skills。 。 。 .

如何教你的编码代理

包船技巧 教编码剂 规划特征,脚手架与 df-scaffold,用 df-react 并执行生成的代码.

npx df-skills --claude

在升级了软件包以获得新版本后再运行. 添加 --principles 还将方案拟订原则与 CLAUDE.md 财务报告和审定财务报表 AGENTS.md。 。 。 .

许可证

麻省理工学院

版本与发布记录

@domain-first/project-structure 共发布 86 个版本,首次发布于 2026/08/26;过去 12 个月发布了 86 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
8.8.0latest2026/11/121 天前
8.7.12026/11/121 天前
8.7.02026/11/103 天前
8.6.12026/11/049 天前
8.6.02026/11/049 天前
8.5.12026/11/0310 天前

关于 @domain-first/project-structure 的常见问题

@domain-first/project-structure 是什么?

用 CLI 构建和管理您的域- 第一项目结构

如何安装 @domain-first/project-structure?

在项目目录运行 npm install @domain-first/project-structure,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 df-init、df-lint、df-graph、df-react、df-skills、df-upgrade、df-scaffold、df-integration,可以用 npx df-init 直接运行。

@domain-first/project-structure 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@domain-first/project-structure 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@domain-first/project-structure 可以商用吗?

@domain-first/project-structure 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@domain-first/project-structure 的下载量有多少?

根据 npm 官方下载统计,@domain-first/project-structure 在 2026/10/13 – 2026/11/11 这 30 天内被下载 6,840 次,日均约 228 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@domain-first/project-structure 还在维护吗?

最新版本 8.8.0 发布于 2026/11/12(1 天前);至今共发布 86 个版本,其中过去 12 个月发布了 86 个;首次发布于 2026/08/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。