案例
本文以 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()
}
说明:
HELLO_RESOURCE描述资源身份:id、kind、source。source: { type: 'config' }表示配置型资源。- declare(同步、轻量):只把身份登记进
resourceRegistry。生产 loader 与 dev 注册路径都约定 uniformdeclare/activate优先、nameddeclareHello/activateHello兜底,所以脚手架两个都导出。 - activate(异步、重量):骨架暂无业务实现;你在这里动态 import 组件/能力/槽位,资源未被禁用才执行。
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),不参与运行时资源闭包。