# @client-compose/client 中文文档

规范地址：https://npmcn.com/package/%40client-compose/client/

版本：0\.16\.0
npm 元数据更新时间：2026-10-29T19:56:21.226Z
中文译文更新时间：2026-11-10T01:44:56.881Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40client-compose/client
原文对照：https://npmcn.com/package/%40client-compose/client/?lang=original
项目主页：https://github.com/client-compose/client-compose/tree/main/clients/typescript/core#readme
源码仓库：https://github.com/client-compose/client-compose

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：187 kB，28 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- 首次发布：2026-10-19T14:06:43.697Z
- 最新版本发布：2026-10-29T19:56:20.870Z
- 近 30 天下载量：2945（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：18（近 12 个月 18 个）

## 中文简介

框架不可知客户编制客户:岛屿登记、筛选请求和提供规划.

## 安装

```sh
npm install @client-compose/client
```

也可以使用：`pnpm add @client-compose/client`、`yarn add @client-compose/client`、`bun add @client-compose/client`

## README

# @ client- compose/ 客户端

框架不可知客户端 [客户端编译](https://github.com/client-compose/client-compose)数字 : 由客户拥有的岛屿组成的服务器屏幕协议.

等级 : **核心项目** 议定书: **页:1** 任何联署材料运行时间 `fetch` (浏览器,反应原生,节点20+)

```sh
npm install @client-compose/client
```

> 使用反应还是反应原生? 使用 [`@client-compose/react`](https://www.npmjs.com/package/@client-compose/react), (中文(简体) ), 以此为基础.

## 使用量

`IslandRegistry<R>` 将岛屿类型和版本映射给渲染器. `R` 无论你的UI做的是什么 (一个DOM节点,一个HTML的字符串,一个框架元素),因此这个核心与任何UI层一起工作.

```ts
import { buildRequest, fetchScreen, IslandRegistry, plan } from "@client-compose/client";
import { ProfileHeaderV2 } from "./islands.generated"; // from @client-compose/codegen

const registry = new IslandRegistry<HTMLElement>()
  .register(ProfileHeaderV2, (props) => renderProfileHeader(props));

const request = buildRequest(registry, "profile", { platform: "web", appVersion: "1.4.0" }, { userId });
const response = await fetchScreen("https://api.example.com/compose", request, {
  headers: { Authorization: `Bearer ${token}` },
});

const islands = plan(registry, response, {
  onSkipped: (entry, reason) => console.warn("skipped island", entry.key, reason),
});
container.replaceChildren(...islands.map((island) => island.render()));
```

-   **`buildRequest`** 发送岛类型和版本 这个客户端可以渲染, 所以作曲家 永远也回不来.
-   **`plan`** 返回可转换岛屿。 错误的岛屿被省略,除非您通过 `onError`; 类型、版本或状态不明的岛屿被跳过和报告.
-   **`registry.declare(...)`** 应用程序在服务器上等其它地方制作的名字: 注册人无法制作它们,但动作说应用程序可以绘制它们,并更改它们 实体对其适用(第5.3节).
-   **`fetchScreen`** 读取屏幕的流到它的末端,然后返回整个. 它会扔 `ScreenFetchError` (与 `status` 财务报告和审定财务报表 `body`非-2xx回复,并接受习惯 `fetch` 作为它的第四个论点.

## 流线

屏幕作为溪流而来(第4.6段):它的头,任何岛屿还没有准备好 `pending`,则 每个作为作曲家的人都会决定. **`openScreen`** 头一进去就解决了,这样你就可以 显示屏幕并填入:

```ts
const stream = await openScreen(baseUrl, request, init);
let screen = stream.head;
show(plan(registry, screen)); // pending islands are their placeholders, or left out
for await (const island of stream.islands) {
  screen = withIsland(screen, island);
  show(plan(registry, screen));
}
```

-   为岛屿登记占地者 `registry.registerPlaceholder(Descriptor, () => …)`数字 : `plan` 在岛上待决时展示 没有它,这个岛就被排除在外,直到它到达.
-   一条溪流从不带的岛屿(断了的连接) 是一个错误, `incomplete`, (中文(简体) ), 可重试.
-   `collectScreen(stream)` 读取其余部分并返回整个屏幕.
-   身体读来读来读去 `fetch` 给一个可读流(浏览器、节点、德诺、邦、, 财务报告和审定财务报表 `expo/fetch` (原始内容存档于2018-09-31). React Industrial. 反应原生的内置 `fetch` 没有,所以有屏幕 马上就到.

## 行动

```ts
import { ActionFetchError, callAction } from "@client-compose/client";
import { FollowUserV1 } from "./actions.generated"; // from @client-compose/codegen

const res = await callAction("https://api.example.com/compose", FollowUserV1, { userId }, {
  client: { platform: "web", appVersion: "1.4.0" },
  islands: registry.capabilities(), // updates come at versions the app can render
  init: { headers: { Authorization: `Bearer ${token}` } },
});
if (res.status === "ok") showFollowers(res.result.followers); // and apply res.effects (spec §5.3)
else if (res.error.code === "blocked") showBlocked();
else showGenericError(); // codes added after this app was built
```

-   宣布的错误是结果(`status: "error"`每个动作键入。 其他的,比如说 `invalid_input`, (中文(简体) ), `unauthenticated` 或者说 `action_failed`掷出 `ActionFetchError` 与 `status` 财务报告和审定财务报表 `code`。 。 。 .
-   每一次通话都会发出一个新的一能键. 过 `idempotencyKey` {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}你自己来重试同样的意图.

在运行时不会验证道具; 生成类型 [`@client-compose/codegen`](https://www.npmjs.com/package/@client-compose/codegen) 让他们留在 与作曲家同步.

## 有页的岛屿

岛屿入口载着 `next` 岛上的网页更多(第4.5节). `fetchIsland(baseUrl, buildIslandRequest(screen, params, entry, client, entry.next))` 获取 下一页: 岛上再次进入, 加上那页的道具和它自己的 `next`。没有光标,它 重新解决该岛的第一页。 反应束缚 `usePages` 这样做是为了你.

## 字符串

每个词都来自作曲家(spec §4.7). 由具有下列特征的描述者对岛屿进行登记: 宣布弦,它的制造者道具有它们作为 `t`,在屏幕的语言,计数 字符串按其复数规则选择其词:

```ts
registry.register(ArticleListV1, (props) => `${props.t.heading}: ${props.t.articleCount({ count: props.total })}`);
```

应用字符串来自 `POST {base}/strings`数字 :

```ts
const response = await fetchStrings(baseUrl, client);
const t = appStrings(AppStrings, response); // t.retry, t.uploaded({ count, total })
```

发送该人的语言作为 `client.locale`· ; `preferredLocale` 从设备的标签中选择,或者 接受语气标题( C)`preferredLocale("pl-PL,pl;q=0.9")` 实值 `"pl-PL"`)和作曲家 用它最近的语言回答. `formatString(template, values, plurals)` 财务报告和审定财务报表 `pluralCategory(plurals, count)` 还有其他事 在测试中,假作曲家回答 `strings: () => stringsResponse("en", { … })`, (中文(简体) ), 财务报告和审定财务报表 `island(key, Descriptor, props, { strings })` 给一个岛屿 其弦. `catalogStrings(catalog)` 读取目录文件( codegen's) `catalog`作曲家会寄给它 用来测试 真实词 : `t(Descriptor)`, (中文(简体) ), `app(AppStrings)`, (中文(简体) ), `island(…)` 与它的弦,和 `stringsResponse()`。 。 。 .

## 测试

`@client-compose/client/testing` 是一个假作曲家 测试, 没有自己的测试框架. `createFakeGateway` 回答处理器的屏幕和动作请求并记录它们;通过它 `fetch` 给客户的 构建响应 `island`, (中文(简体) ), `islandError`, (中文(简体) ), `screen`, (中文(简体) ), `screenError`, (中文(简体) ), `actionOk`, (中文(简体) ), `actionError` 财务报告和审定财务报表 `actionFailure`,按生成的描述符键。 A 类 `screen` 实值 为了控制每个岛屿的到来,请回答 `streamedScreen(id, [island(…), pending(key, Descriptor)])`,然后调用它的 `send(entry)`, (中文(简体) ), `end()`, (中文(简体) ), 或者说 `cut()` 连接中断.

```ts
import { actionError, createFakeGateway } from "@client-compose/client/testing";

const gateway = createFakeGateway({
  actions: { follow: () => actionError(FollowUserV1, { code: "blocked" }) },
});
const res = await callAction(baseUrl, FollowUserV1, { userId }, { client, islands: {}, fetch: gateway.fetch });
assert.equal(gateway.actionRequests()[0].input.userId, userId);
```

对于被称为全球的代码 `fetch` 自己,像一个完整的应用 在测试, `installFakeGateway(handlers)` 把假作曲者放在原位; 打电话 `restore()` 后来.

对于反应, `@client-compose/react/testing` 添加围绕它构建的提供者配置 .

## 通过您的服务器

`@client-compose/client/proxy` 将浏览器的屏幕、岛屿和行动请求传递给作曲家 通过您的服务器, 它可以添加浏览器不能持有的东西, 例如保存在一个 httply Cookie. (原始内容存档于2018-09-27). `createComposerProxy({ baseUrl, client, headers, onActionResponse })` 检查每个 请求(任何人都可以用任何东西调用服务器端点),设置客户端上下文和信头, 并返回作曲者的失败作为数据. `@client-compose/react`是因为 `viaProxy` 是浏览器 半个.

字符串也会通过您的服务器 : `proxy.loadStrings()`。 。 。 .

## 链接

-   [协议规格](https://github.com/client-compose/client-compose/blob/main/spec/PROTOCOL.md)
-   [实例](https://github.com/client-compose/client-compose/tree/main/examples/todo)

## 常见问题

### @client-compose/client 是什么？

框架不可知客户编制客户:岛屿登记、筛选请求和提供规划\.

### 如何安装 @client-compose/client？

在项目目录运行 npm install @client-compose/client，或使用 pnpm add / yarn add / bun add。

### @client-compose/client 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @client-compose/client 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @client-compose/client 可以商用吗？

@client-compose/client 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @client-compose/client 的下载量有多少？

根据 npm 官方下载统计，@client-compose/client 在 2026/10/10 – 2026/11/08 这 30 天内被下载 2,945 次，日均约 98 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @client-compose/client 还在维护吗？

最新版本 0\.16\.0 发布于 2026/10/30（11 天前）；至今共发布 18 个版本，其中过去 12 个月发布了 18 个；首次发布于 2026/10/19。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

