组装

本文介绍如何把 core 与资源组装成网站/应用:开发用 clientx run,生产用 clientx build 后由 core 运行时从 manifest.json 加载(目录即真相),并且全程只有一个 React 实例。

1. 组装成网站/应用

「组装」= 选一组资源(闭包)+ 构建产物 + 由 core 运行时把它们装起来。因为资源是解耦的,同一个 core 可以组装出不同形态:

# 形态一:完整应用(消息/用户/AI/连接/加密)
node scripts/clientx.mjs build --resources client,userx,msgx,agix,conn,e2ee

# 形态二:官网(应用壳 + 站点框架 + 官网站点)
node scripts/clientx.mjs build --resources client,sitex,portal

# 形态三:只出一个资源组合(资源级独立成立)
node scripts/clientx.mjs build --resources sitex
node scripts/clientx.mjs build --resources portal

产物统一落在 dist/。部署时把 dist/ 交给任意静态服务器即可(见「安装」页方式 B)。

2. clientx run:开发服务器

node scripts/clientx.mjs run                        # 默认组合: client+userx+msgx+agix+conn+e2ee
node scripts/clientx.mjs run --resources sitex      # 只声明/激活 sitex 闭包(VITE_RESOURCES=sitex)
node scripts/clientx.mjs run --resources client,sitex,portal   # 本地调试官网

--resources 会设置 VITE_RESOURCES,dev 的注册路径(src/resource/register.ts 的 glob 驱动)只 declare/activate 指定闭包;未设时回退默认组合。clientx run 直连本地 vite(透传 stdio 与信号,Ctrl+C 干净关停),默认端口 3007。

dev 与 prod 行为对齐:declare 同步、轻量;activate 异步、按依赖序;用户关闭的资源在 import/declare/activate 之前过滤(不下载、不激活)。

3. core 运行时从 manifest 加载(目录即真相)

生产 boot 由 src/core-loader.ts 驱动,core 里不出现任何具体资源名 —— 全部来自 dist/resource/manifest.json:

关键步骤:

  1. 拉 manifest:GET /resource/manifest.json 得到 { resources: [{ id, entry, deps }] }。目录即真相 —— dist/resource/ 里有什么,应用就装什么;改 manifest(或直接增删资源目录)即改变组装结果。
  2. 注入 importmap:index.html 已内联(构建期注入),loader 幂等跳过。
  3. 预载 vendor:shared-vendor.js + vendor-i18n.js,保证资源模块解析到同一实例。
  4. 过滤禁用:持久化覆盖(用户关闭)在 import/declare/activate 之前过滤。
  5. 拓扑加载:按 deps 拓扑序 import('/resource/<id>/register.js'),先依赖后依赖者。
  6. declare → activate:全部 declare 后 applyPersistedOverrides(),再依依赖序逐个 activate。

4. 单一 React 实例

组装的核心保证是全应用只有一个 React(及其配套)实例,由 importmap 实现。以下为 --resources client,sitex,portal 闭包生成 importmap 的示意摘录(真实产物 64 个条目,此处只列代表性键;@/resource/<id>/ 结尾是目录前缀兜底):

{
  "imports": {
    "react": "/assets/shared-vendor.js",
    "react/jsx-runtime": "/assets/shared-vendor.js",
    "react-dom": "/assets/shared-vendor.js",
    "@tanstack/react-router": "/assets/shared-vendor.js",
    "@tanstack/react-query": "/assets/shared-vendor.js",
    "zustand": "/assets/shared-vendor.js",
    "i18next": "/assets/vendor-i18n.js",
    "react-i18next": "/assets/vendor-i18n.js",
    "@clientx/runtime/lib/kernel/instance": "/vendor/runtime/lib/kernel/instance.js",
    "@clientx/common/components/markdown-content": "/vendor/common/components/markdown-content.js",
    "@/resource/sitex/blocks": "/resource/sitex/blocks/index.js",
    "@/resource/sitex/": "/resource/sitex/",
    "@/resource/portal/": "/resource/portal/"
  }
}

5. 组合清单速查

组合命令产物
默认应用clientx buildclient+userx+msgx+agix+conn+e2ee
官网clientx build --resources client,sitex,portal应用壳 + 站点框架 + 官网站点
资源独立clientx build --resources portal闭包 [sitex, portal],无需 client
只出框架clientx build --resources sitex仅 sitex

6. 下一步