案例

本文以 hello 最小示例资源为主线:先看 clientx create 生成的完整源码,逐文件说明,再演示如何下载资源包并组装进应用。

1. 生成 hello

node scripts/clientx.mjs create hello --deps client

输出(节选):

[clientx] created resource "hello" at src/resource/hello/
  package.json  { name: @me/hello, clientx: { id: hello, kind: app, deps: [client], entry: register.ts } }
  register.ts   declareHello() + activateHello()(资源根,与既有资源同构)
  i18n/zh.json + i18n/en.json  {}
[clientx] 下一步: node scripts/clientx.mjs build --resources hello

2. 完整源码

src/resource/hello/package.json

{
  "name": "@me/hello",
  "clientx": {
    "id": "hello",
    "kind": "app",
    "deps": [
      "client"
    ],
    "entry": "register.ts"
  }
}

说明:clientx 字段描述资源自身 —— id 与目录名一致,kind 为 app,deps 声明依赖 client(写入后闭包解析与源码 import 推导取并集),entry 固定为 register.ts。

src/resource/hello/register.ts

// src/resource/hello/register.ts
// hello 资源自声明骨架(clientx create 生成)。
// declareHello:同步登记资源身份(轻量、进主 chunk);
// activateHello:异步动态 import 重量实现(未被禁用才 activate)。
import { resourceRegistry } from '@clientx/runtime/lib/kernel/instance'
import type { Resource } from '@clientx/runtime/lib/kernel/types'

export const HELLO_RESOURCE: Resource = { id: 'hello', kind: 'app', source: { type: 'config' } }

// 双约定导出:uniform declare/activate(loader 优先)+ declareHello/activateHello(dev 静态路径/旧命名)。
export function declare(): void {
  resourceRegistry.declare(HELLO_RESOURCE)
}
export function declareHello(): void {
  declare()
}

export async function activate(): Promise<void> {
  // 骨架无重量实现;在此动态 import 业务模块。
}
export async function activateHello(): Promise<void> {
  await activate()
}

说明:

src/resource/hello/i18n/zh.json / en.json

{}

语言包模板。随资源构建进 dist/resource/hello/i18n/,按启用资源注入 i18next(禁用资源不下载语言包)。

3. 把 hello 做成「会做事」的资源

骨架自声明能构建、能随闭包加载,但还没有 UI。加一个页面需要:在 declare 里注册路由(组件懒加载),在 activate 里 import 并注册能力/槽位。参照内置资源(如 msgx/register.ts)的模式:

export function declareHello(): void {
  resourceRegistry.declare(HELLO_RESOURCE)
  routeRegistry.register('hello', [
    { id: 'hello-page', path: 'hello', parent: ROUTES.app, component: () => import('./modules/hello-page') },
  ])
}

export async function activateHello(): Promise<void> {
  const { HelloBadge } = await import('./components/hello-badge')
  slotRegistry.register('nav:hello', HelloBadge)
}

然后在 src/resource/hello/modules/hello-page.tsx 里写一个页面组件即可 —— 资源内的代码照常使用 @clientx/*、@/resource/client/*(依赖允许的跨资源引用)与 t()。

4. 构建 hello

node scripts/clientx.mjs build --resources hello,client

闭包 = [client, hello](依赖先行)。产物:

dist/resource/client/**     # client 资源包(依赖)
dist/resource/hello/        # hello 资源包
dist/resource/manifest.json # { resources: [{ id: hello, entry: /resource/hello/register.js, deps: [client] }] }

5. 组装 hello 进应用

方式 A:开发服务器

node scripts/clientx.mjs run --resources client,hello

访问 http://localhost:3007,hello 资源随闭包声明/激活。

方式 B:从下载包组装

下载 resource-hello-example.tar.gz(clientx create hello --deps client 生成后的源码包)并解压:

tar xzf resource-hello-example.tar.gz     # 解压出 hello/
cp -r hello/ <你的core>/src/resource/hello/

再在 core 仓库里:

cd <你的core>
npm install
node scripts/clientx.mjs build --resources client,hello
node scripts/clientx.mjs run --resources client,hello

6. 组装官网(含本平台)

# 下载 core 源码 → 解压 → npm install
node scripts/clientx.mjs build --resources client,sitex,portal   # 全量官网(含 client)
node scripts/clientx.mjs run --resources client,sitex,portal     # 开发调试

portal 资源负责官网首页、下载页与版本日志;下载产物在 /downloads/(clientx-core-source.tar.gz / clientx-core-prebuild.tar.gz / 各 resource-<id>-source.tar.gz / resource-hello-example.tar.gz)。开发者文档与帮助中心是独立的 Astro 静态资源(docs / help),不参与运行时资源闭包。