Activepieces core 包架构:@activepieces/core-* 依赖边界与模块分层设计
【免费下载链接】activepiecesAI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces
导读
本文讲解 Activepieces 仓库中packages/core/目录下核心包的设计规范:命名规则、依赖边界(thin/thick 分层)、以及"pieces 与 engine 可依赖 core-*、但严禁依赖@activepieces/shared"这一关键约束。通过阅读本文,你将理解 Activepieces 如何将跨切面库代码组织为框架无关、可打包(bundleable)的基础库,以及@activepieces/pieces-framework如何在其中承担符号再导出的桥梁职责。该规范在仓库中由 .claude/rules/core-packages.md 强制约束,是参与 Activepieces 核心代码开发、新增 core 包或排查依赖循环时必须遵循的架构底线。
一、命名规则:packages/core/<name>与@activepieces/core-<name>
packages/core/目录下的每个包在 npm workspace 中统一命名为@activepieces/core-<name>。以 packages/core/utils 为例:
- 目录:
packages/core/utils - 包名:
@activepieces/core-utils(当前版本 0.6.2) - 构建产物入口:
./dist/src/index.js(CJS 构建,"type": "commonjs")
同理,packages/core/piece-types→@activepieces/core-piece-types、packages/core/formula→@activepieces/core-formula、packages/core/execution→@activepieces/core-execution,在各自的 package.json 中均有对应体现。
这一命名并非随意设计:统一的core-前缀让所有基础库在一众 workspace 包中一眼可辨,也便于构建脚本与 lint 规则对"thin 成员"做批量校验——例如检查它们是否违反了禁止依赖@activepieces/shared、@activepieces/server-*、piece 包与 web/React 包的约束。
二、唯一例外:@activepieces/shared是厚(thick)成员
packages/core/shared是目录中唯一的例外,它保留原名@activepieces/shared(而非core-shared),这一点在 packages/core/shared/package.json 中可见:
{ "name": "@activepieces/shared", "version": "0.162.0", "type": "commonjs", "sideEffects": false, "dependencies": { "@activepieces/core-execution": "workspace:*", "@activepieces/core-formula": "workspace:*", "@activepieces/core-piece-types": "workspace:*", "@activepieces/core-utils": "workspace:*", "dayjs": "1.11.9", "expr-eval": "2.0.2", "socket.io-client": "4.8.1", ... } }它是该目录中唯一"厚、应用级"(thick, app-level)的成员,具有三个显著特征:
- 携带重依赖:
dayjs(日期处理)、expr-eval(公式表达式求值)、socket.io-client(WebSocket 客户端)等重量级第三方依赖都沉淀在这里; - 承载 DB/EE/管理面 schema:从其 src 目录结构 可以看出,它同时包含
lib/automation/(app-connection、pieces、tables、webhook、websocket 等自动化领域模型)、lib/core/(authentication、file、flag、user 等平台核心模型)、lib/ee/(agent、alerts、billing、scim、secret-managers 等企业版功能模型)以及lib/management/(platform、project、template 等管理面模型)——大量领域实体与 DTO 都在此定义; - 依赖方向反转:它依赖目录内的 thin 成员(
core-utils、core-piece-types、core-formula、core-execution),而不是反过来。这一点直接体现在其dependencies字段中的四个workspace:*引用上。
2.1 目录内顺序:thin → thick
整个packages/core/目录按"从薄到厚"(thin → thick)组织所有跨切面库代码:
packages/core/utils → @activepieces/core-utils (最薄) packages/core/piece-types → @activepieces/core-piece-types packages/core/formula → @activepieces/core-formula packages/core/execution → @activepieces/core-execution (薄、可打包) packages/core/shared → @activepieces/shared (最厚,唯一 thick 成员)从依赖关系看,这一顺序也是拓扑有序的:
- core-utils 只依赖
deepmerge-ts、ipaddr.js、nanoid、zod等纯工具库,不依赖任何兄弟 core 包; - core-piece-types 依赖
core-utils; - core-execution 依赖
core-utils与core-piece-types,并直接使用dayjs、semver、socket.io-client、zod; - core-formula 仅依赖
dayjs、expr-eval,保持独立; - shared 依赖上述全部四个 thin 成员。
该依赖图必须保持无环(acyclic),这是防止打包膨胀与循环引用的硬性要求。
三、thin 成员:框架无关的"薄"基础库
thin 成员(core-utils、core-piece-types、core-formula、core-execution)被定义为框架无关(framework-agnostic)的基础库,其约束非常严格:
它们严禁import 自
@activepieces/shared、@activepieces/server-*(server 侧任何包)、任何 piece 包,或任何 web/React 包。
3.1 薄成员到底薄在哪
"薄"并非指代码量少,而是指依赖面窄、领域职责单一。以 core-utils 的 src 结构 为例,它只提供纯工具与基础设施:
- 错误与断言:
activepieces-error.ts、assertions.ts、form-errors.ts、friendly-piece-error.ts、try-catch.ts - 通用工具:
id-generator.ts(nanoid 生成 ID)、object-utils.ts、mustache-utils.ts、color.ts、locale.ts - 安全与网络:
ssrf-ip-classifier.ts(SSRF 防护的 IP 分类) - 缓存与分页:
byte-lru-cache.ts、seek-page.ts(SeekPage分页模型,被 framework 与 server 广泛复用) - 领域辅助模型:
connection-template.ts、permission.ts、project-role.ts、multipart-file.ts
同样,core-piece-types 的 src 聚焦于"类型契约"层:piece.ts、engine.ts、execution.ts、flows.ts、triggers.ts、forms.ts、tables.ts、mcp-piece.ts等,只定义类型与轻量校验逻辑,不包含任何应用实现;core-formula 的 src 则只包含公式求值的四个文件(formula-evaluator.ts、function-implementations.ts、function-registry.ts、function-type-checker.ts),是对expr-eval的封装层。
3.2 双格式产物与 sideEffects
thin 成员以双格式(dual-format)发布——同时输出 CJS 与 ESM 构建,并声明"sideEffects": false,以便打包器(bundler)对未使用的导出做 tree-shaking。这一点在 core-utils 的 package.json 中可见端倪:"main": "./dist/src/index.js"、"typings": "./dist/src/index.d.ts"(CJS 产物),而其 tsconfig.json 使用"module": "esnext"、"moduleResolution": "bundler"面向 ESM 生态;tsconfig.lib.json 则用"module": "commonjs"产出 CJS。sideEffects: false的语义是:该模块的所有导入/导出均为纯代码,不附带全局副作用(如注册全局对象、修改原型等),因此可以被安全地摇树优化。
注意:仓库当前实际以
"type": "commonjs"+dist/形式发布,双格式产出由各包 tsconfig 配置驱动;从源码结构看,thin 成员被设计为可在 engine(沙箱内)与 web 打包场景中安全复用,这正是"bundleable"的含义。
四、导入边界(关键约束):pieces 与 engine 的依赖红线
规则的核心是按包粒度(per-package)强制实施的导入边界,而非按文件夹名:
pieces 和 engine 可以 import
@activepieces/core-utils、@activepieces/core-piece-types、@activepieces/core-formula、@activepieces/core-execution,但永远不能import@activepieces/shared(即packages/core/shared)。
这一设计的意义在于:
- **pieces(组件)**运行在 engine 的隔离沙箱中,只能接触到框架无关的薄库;如果 pieces 直接依赖
@activepieces/shared,就会把整个平台层的领域模型、socket.io-client、dayjs等重依赖拉进沙箱打包产物,显著增大 bundle 体积,并可能造成沙箱内外的类型/实例不一致; - engine是执行引擎本体,它同样只依赖薄库来保持自身轻量、可独立部署(参见 packages/server/engine/package.json,其中仅声明了
@activepieces/core-utils与@activepieces/core-formula两个 core 依赖)。
4.1 为什么 pieces 能拿到 shared 里的符号:pieces-framework 的再导出
既然 pieces 不能直接 import@activepieces/shared,那 pieces 开发中常见的FlowRunId、ProjectId、SeekPage等类型从哪来?答案在@activepieces/pieces-framework。它是 pieces 与 core 库之间的唯一合法桥梁,将 thin 成员中的符号**再导出(re-export)**给所有 piece:
以 packages/pieces/framework/src/index.ts 为例:
// 从 @activepieces/core-utils 再导出 export type { SeekPage } from '@activepieces/core-utils'; // 从 @activepieces/core-piece-types 再导出大量 piece 契约 export { ... } from '@activepieces/core-piece-types';在 framework 的 package.json 中同样可以看到它只声明了@activepieces/core-utils与@activepieces/core-piece-types两个 core 薄库依赖(workspace:*)。各 piece 包只需import自@activepieces/pieces-framework,由 framework 决定哪些 thin 符号可以被暴露——这既满足了 pieces 的开发体验,又不破坏导入边界。
五、依赖图与分层合理性
综合以上信息,可以得到完整的 core 依赖图:
@activepieces/core-utils(最薄,零 core 依赖) │ ├──→ @activepieces/core-piece-types │ │ │ └──→ @activepieces/core-execution │ └──→ @activepieces/shared(厚,依赖全部四个 thin 成员) │ ├──→ pieces-framework(再导出 thin 符号给 pieces) └──→ server-*(应用层,可自由依赖 shared)从源码结构看,这一分层带来三点收益:
- 可测试性:thin 库职责单一,如 core-piece-types 自带
ai-providers.test.ts测试,vitest 可直接单测; - 可打包性:engine 与 pieces 的沙箱产物只包含薄库代码,
sideEffects: false保证 tree-shaking 生效; - 无环保证:依赖方向永远是从厚到薄(thick 依赖 thin),杜绝了跨层反向引用导致的循环依赖与初始化死锁。
六、参与开发时的自查清单
在新增或修改packages/core/下的代码时,请对照以下规则自查:
| 检查项 | 规则 | 依据 |
|---|---|---|
| 命名 | packages/core/<name>→@activepieces/core-<name> | 各 package.json 的name字段 |
| 例外 | packages/core/shared保持@activepieces/shared | shared/package.json |
| 分层 | 目录内顺序 thin → thick:utils → piece-types → formula → execution → shared | 各包dependencies中的workspace:*引用 |
| thin 约束 | thin 成员不得 import@activepieces/shared、@activepieces/server-*、任何 piece 包、任何 web/React 包 | .claude/rules/core-packages.md 规则原文 |
| 无环 | 依赖图必须保持无环,shared 依赖 thin、thin 之间仅向前依赖 | 各包 package.json 依赖声明 |
| 导入边界 | pieces 与 engine 可依赖四个 thin 成员,严禁依赖 shared;pieces 的符号经@activepieces/pieces-framework再导出 | framework/src/index.ts |
| 构建 | thin 成员双格式(CJS + ESM)、"sideEffects": false | core-utils/package.json 与 tsconfig.lib.json |
这套规范直接服务于 Activepieces 的运行时架构:engine 在隔离沙箱中执行 piece,沙箱产物必须最小化,因此所有被 piece 与 engine 共享的符号都收敛在薄库中,由 framework 统一暴露;而平台级领域模型则安心沉淀在厚库shared中,供 server 应用层使用。理解并遵守这一边界,是避免"pieces 拖入整个平台依赖"这一经典架构事故的前提。
【免费下载链接】activepiecesAI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考