Huly Core 深度指南:Huly 平台核心包库的架构、构建与二次开发实践
2026/9/12 4:14:35 网站建设 项目流程

Huly Core 深度指南:Huly 平台核心包库的架构、构建与二次开发实践

【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform

Huly Core 是从 Huly 全栈项目管理平台中抽取出来的一组核心 TypeScript 包集合,承载着 Huly 生态的底层数据模型、客户端访问层、文本处理引擎与平台运行基础设施。本文以 foundations/core/README.md 为主线,结合仓库中 Rush 配置 与各包源码,系统讲解 Huly Core 的包组成、环境要求、基于 Rush 的安装/构建/测试/发布全流程,并延伸介绍 API Client 的编程式接入方式,帮助你基于这些可复用的核心包构建自定义应用或集成 Huly 能力到现有项目。

Huly Core 是什么

Huly Core 是 Huly 平台核心包的独立集合,位于本仓库的 foundations/core 目录。它是从 Huly Platform 中抽取出的基础构件:包括核心数据模型(core data models)、客户端库(client libraries)、文本处理引擎(text processing engines)以及平台工具集(platform utilities)。

这些包被设计为可复用、模块化、框架无关(reusable, modular, framework-agnostic),其目标场景有两个:

  • 在 Huly Platform 之上构建自定义应用;
  • 将 Huly 功能集成进已有项目。

从目录结构看,foundations/core/packages 下共维护了 26 个 npm 包,全部以@hcengineering/作用域发布。Rush 清单 rush.json 中每个包都声明了shouldPublish: true(除内部脚本包@hcengineering/scripts外),表明它们都是面向 npm 生态对外发布的正式产物。

包清单详解

Core Packages:数据模型与平台运行时

  • @hcengineering/core— 核心数据模型、类型定义与平台基础抽象。该包的 入口文件 对外导出classeshierarchymemdboperationsoperatorquerystoragetxbackupversioning等模块。其中 classes.ts 定义了贯穿全平台的基石类型:Ref<T>(强类型文档引用)、Doc(所有文档的基接口,包含_idspacemodifiedOnmodifiedBy等统一字段)、Class<T>(类描述符,可携带domainextendsimplements、索引配置)、AttachedDoc(挂载到父文档的附属文档)、Space(空间模型)以及AccountRoleTxSequenceBlob等抽象。
  • @hcengineering/platform— 平台运行时、插件系统与依赖注入。核心源码在 platform.ts 中:它定义了PRI(Platform Resource Identifier)机制——几乎平台中的一切都是Resource,通过形如core.string.ClassLabel的字符串标识来引用翻译文本、SVG 图标等资源;并提供plugin()mergeIds()用于声明插件 ID 命名空间、Id/Plugin/IntlString/StatusCode等类型化字符串。同包还包含 i18n、metadata、event、resource、status 等基础模块。
  • @hcengineering/model— 数据模型定义与 Schema 管理。其 dsl.ts 实现了一套模型 DSL:用 TypeScript 装饰器与toposort拓扑排序收集ClassTxes,将类定义自动转化为一系列Tx(事务)作为模型元数据,供服务端加载与迁移使用。

Client Libraries:客户端访问与同步层

  • @hcengineering/client— 客户端数据访问与同步层,负责前端与后端的实时数据同步。
  • @hcengineering/client-resources— 客户端共享资源与工具。
  • @hcengineering/api-client— 面向编程式访问的 API 客户端,同时支持WebSocketREST两种协议,其完整使用文档见 api-client/README.md,后文有专门章节展开。
  • @hcengineering/account-client— 账号管理客户端。
  • @hcengineering/collaborator-client— 实时协作文档客户端。
  • @hcengineering/hulylake-client— HulyLake 数据仓库(datalake)客户端。
  • @hcengineering/analytics@hcengineering/analytics-service— 分析与埋点工具及其服务端实现。

Text Processing:文本处理引擎

文本处理是 Huly 文档/评论体系的重要底座,这组包从底层引擎到上层格式逐层分工:

  • @hcengineering/text-core— 核心文本处理引擎;
  • @hcengineering/text— 高层文本处理工具,其 src 下包含基于 ProseMirror/TipTap 的kitnodesmarksmarkup等扩展实现;
  • @hcengineering/text-html— HTML 文本的渲染与解析;
  • @hcengineering/text-markdown— Markdown 支持;
  • @hcengineering/text-ydoc— Yjs 文档集成,为协同编辑提供 CRDT 基础。

Utilities:平台工具

  • @hcengineering/query— 查询语言与执行引擎;
  • @hcengineering/storage@hcengineering/storage-client— 存储抽象与实现、存储客户端;
  • @hcengineering/rank— 基于 LexoRank 的排序工具(Rank类型定义见 classes.ts);
  • @hcengineering/retry— 重试逻辑与容错模式;
  • @hcengineering/rpc— RPC 通信层;
  • @hcengineering/token— Token 管理与认证工具(在 Rush 清单中以@hcengineering/server-token发布)。

此外,foundations/core/packages 目录中还维护着 README 未单独列出、但同样对外发布的辅助包:measurementsmeasurements-otlp(可观测性指标)与postgres-base(PostgreSQL 基础封装),均在 rush.json 的projects清单中登记。

环境要求与前置条件

开始构建前,系统需要满足:

依赖要求说明
Node.jsv20.11.0 或更高(README 要求)实际 rush.json 中声明的支持范围更宽:>=18.20.3 <19.0.0 \|\| >=20.14.0 <25.0.0,建议以 v20 LTS 为准
Rush微软的可扩展 monorepo 管理工具本仓库锁定引擎版本5.158.1,包管理器使用pnpm 10.15.1

Rush 的 "version selector" 机制会保证全局安装的任意版本在仓库内按rushVersion声明表现一致;common/scripts/install-run-rush.js等脚本也会自动使用该版本。

安装与构建全流程

安装

首先全局安装 Rush:

npm install -g @microsoft/rush

然后在仓库根目录(即 foundations/core)依次执行:

rush install rush build

rush install会按照 rush.json 中的pnpmVersion安装本地副本的 pnpm,为全部 26 个包建立统一的依赖树与符号链接;rush build按拓扑依赖顺序增量构建所有包。

构建与热更新

常用构建命令对照:

rush build # 增量构建所有包(利用 build cache) rush rebuild # 忽略缓存,全量重新构建 rush build:watch # 开发模式:以 watch 模式持续构建,包含 build 与 validate 阶段

其中rush build:watch在开发迭代时最为常用——修改任意包的源码后,依赖它的包会被自动重编译,配合rushx test可以快速完成开发闭环。

项目结构更新

当项目结构发生变化(新增包、调整依赖关系)时,需要重新关联并重建:

rush update rush build

rush update会重新解析依赖树并更新common/temp下的安装产物,通常在修改 rush.json 的projects清单或各包package.json依赖后执行。

故障排查:构建缓存

如果构建失败但代码本身没有问题,常见原因是本地 build cache 损坏。此时删除缓存并全量重建:

rm -rf common/temp/build-cache rush rebuild

(Rush 的构建缓存机制详见 Rush 官方 build cache 文档,仓库内该缓存路径位于 common/temp 下。)

测试

执行全部包的测试:

rush test

若要单独运行某个包内的测试,进入该包目录后执行:

rushx test

rushx是 Rush 项目内脚本的执行入口,等价于在该包上下文内运行npm test。各包根目录均配置了独立的 jest.config.js,例如coreplatform包都有对应的src/__tests__目录存放单元测试。

包版本管理与发布

Huly Core 的版本发布使用仓库级脚本bump.js完成。对单个包进行版本号递增:

node ./common/scripts/bump.js -p projectName

其中projectName替换为要发布的包名(如@hcengineering/core)。该脚本位于 common/scripts/bump.js,属于本仓库 monorepo 的公共工具链,同目录下还提供sync-versions.jscheck-versions.js等版本一致性维护脚本。每个包的变更历史记录在各自的 CHANGELOG.md 中。

通过 API Client 编程式接入 Huly

README 特别指出:若想以编程方式与 Huly 交互,应使用 API Client。它提供覆盖全部 Huly 操作的类型化接口,可用来构建集成与自定义应用。以下要点均出自该文档。

两种客户端:WebSocket 与 REST

  • WebSocket 客户端connect):与 Huly 平台 API 保持长连接,适合实时同步场景;
  • REST 客户端connectRest):使用标准 HTTP 请求执行操作,适合一次性/低频率调用。

两者使用相同的连接选项:

import { connect } from '@hcengineering/api-client' // 使用邮箱密码连接(WebSocket) const client = await connect('https://huly.app', { email: 'johndoe@example.com', password: 'password', workspace: 'my-workspace' }) // 使用完毕后关闭连接 await client.close()

REST 版只需将导入改为connectRest,调用方式一致:

import { connectRest } from '@hcengineering/api-client' const client = await connectRest('https://huly.app', { email: 'johndoe@example.com', password: 'password', workspace: 'my-workspace' })

认证方式与连接参数

客户端支持两种认证方式:邮箱 + 密码Token。认证成功后,客户端拥有与对应用户相同的资源访问权限。

  • url:Huly 实例地址,如https://huly.app
  • workspace:目标工作区名称,可在工作区 URLhttps://huly.app/workbench/<workspace-name>中获取;
  • token:可选,认证 Token(与邮箱密码二选一);
  • email/password:可选,账号凭据。

使用 Token 连接:

import { connect } from '@hcengineering/api-client' const client = await connect('https://huly.app', { token: '...', workspace: 'my-workspace' })

查询:findOne 与 findAll

两个核心检索方法均接受三个参数:_class(目标类,结果包含其全部子类)、query(查询条件)与options(可含limitsortlookupprojectiontotal)。

import { SortingOrder } from '@hcengineering/core' import contact from '@hcengineering/contact' // 查询单个文档 const person = await client.findOne(contact.class.Person, { _id: 'person-id' }) // 批量查询 + 排序 + 限制 const persons = await client.findAll( contact.class.Person, { city: 'New York' }, { limit: 10, sort: { name: SortingOrder.Ascending } } )

文档 CRUD

import contact, { AvatarType } from '@hcengineering/contact' // 创建文档 const personId = await client.createDoc(contact.class.Person, contact.space.Contacts, { name: 'Doe,John', city: 'New York', avatarType: AvatarType.COLOR }) // 更新文档 await client.updateDoc(contact.class.Person, contact.space.Contacts, personId, { city: 'New York' }) // 删除文档 await client.removeDoc(contact.class.Person, contact.space.Contacts, personId)

集合(Collections)操作

集合用于管理AttachedDoc——即挂载到父文档上的附属文档,如联系人(Person)下的多个联系方式(Channel):

import contact, { AvatarType } from '@hcengineering/contact' // 向集合中添加附属文档 await client.addCollection( contact.class.Channel, // 附属文档类 contact.space.Contacts, // 空间 personId, // 父文档 id contact.class.Person, // 父文档类 'channels', // 集合名 { provider: contact.channelProvider.Email, value: 'john.doe@example.com' } ) // 更新集合中的附属文档 await client.updateCollection( contact.class.Channel, contact.space.Contacts, channelId, personId, contact.class.Person, 'channels', { city: 'New York' } ) // 从集合中移除附属文档 await client.removeCollection( contact.class.Channel, contact.space.Contacts, channelId, personId, contact.class.Person, 'channels' )

Mixins 扩展

Mixin 允许在不改变原类的情况下为已有文档动态附加属性,例如给Person增加员工(Employee)信息:

import contact, { AvatarType } from '@hcengineering/contact' // 创建 mixin await client.createMixin( personId, contact.class.Person, contact.space.Contacts, contact.mixin.Employee, { active: true, position: 'CEO' } ) // 更新 mixin 属性 await client.updateMixin( personId, contact.class.Person, contact.space.Contacts, contact.mixin.Employee, { active: false } )

从源码理解核心抽象

Huly Core 的设计可以用四个关键词概括:

  1. 类型化 ID 字符串Ref<T>PluginIntlStringResource<T>等都是带品牌标记(branded type)的字符串类型,在编译期提供类型安全,在运行期只是普通字符串,便于序列化与网络传输(见 classes.ts 与 platform.ts)。
  2. 事务(Tx)驱动的数据变更:所有数据修改都以Tx形式表达(TxCreateDocTxMixinTxApplyIf等,见 tx.ts),客户端与服务端通过事务流实现同步与审计。
  3. 类层次与 DomainClass描述符通过extends/implements构成继承体系,并通过domain字段(如DOMAIN_MODELDOMAIN_SPACEDOMAIN_BLOB等,见 classes.ts)决定数据在底层存储中的归属,配合IndexKind声明索引策略。
  4. 插件化资源解析plugin()mergeIds()将每个插件声明为一段扁平命名空间,运行时按 PRI 加载翻译、图标等资源,实现模块解耦(platform.ts)。

许可证与生态

Huly Core 以 EPL-2.0(Eclipse Public License 2.0)开源。在本仓库的 monorepo 布局中,foundations/core是纯核心库层,与 foundations/communication、foundations/net、foundations/server 等并列;上层则由 models(数据模型定义)、plugins(业务插件)、pods(服务部署单元)等构成完整的 Huly 平台。

对于开发者而言,最直接的落地路径是:参照上文在 foundations/core 下完成rush installrush build,随后基于@hcengineering/core的模型抽象定义自己的ClassSpace,通过 api-client 的 WebSocket/REST 客户端与 Huly 服务端交互,再利用text-markdowntext-html等文本包处理富内容,即可在 Huly 平台上搭建出具备文档、任务与实时协作能力的自定义应用。

【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询