webloom-framework 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # WebLoom
2
2
 
3
- WebLoom 是一个与产品领域无关的前端插件生命周期框架。它管理插件产品、运行单元、实例、依赖图、生命周期 Scope、权限租约、消息总线、服务桥和资源缓存;路由、存储、日志、国际化等产品能力通过宿主适配器注入。
3
+ WebLoom 是一个只面向浏览器的插件 Runtime 框架。v1 管理真实的
4
+ `window-main` 和 `shared-worker` JavaScript realm、插件运行单元、实例、
5
+ 依赖图、ResourceScope、权限租约、服务桥和资源缓存;路由、存储、日志、
6
+ 国际化等产品能力由插件或下游应用注入。
4
7
 
5
8
  ## 安装
6
9
 
@@ -10,67 +13,109 @@ pnpm add webloom-framework
10
13
 
11
14
  WebLoom 是 ESM 单包,提供三个入口:
12
15
 
13
- - `webloom-framework`:纯 TypeScript/Worker 可用的核心,不加载 React;
16
+ - `webloom-framework`:浏览器核心,提供 Window/SharedWorker Runtime,不加载 React;
14
17
  - `webloom-framework/react`:Provider、capability、Host、Registry 和 Resource Hooks;
15
18
  - `webloom-framework/testing`:无产品语义的假 Host、假传输和测试辅助。
16
19
 
17
20
  React 是可选 peer dependency。只使用 `webloom-framework` 时不需要安装 React。
18
21
 
19
- ## 最小 Host
22
+ ## 最小 Window Runtime
20
23
 
21
24
  ```ts
22
- import { createPluginHost, type PluginSetup } from "webloom-framework";
23
-
24
- const helloSetup: PluginSetup = (ctx) => {
25
- ctx.provide("hello.service", { value: "world" });
26
- ctx.onDispose(() => {
27
- // 这里释放本插件登记的资源。
28
- });
29
- };
30
-
31
- const host = createPluginHost({
32
- runtimeUnitImplementationRegistry: {
33
- get(pluginId, unitId) {
34
- return pluginId === "hello" && unitId === "hello.window" ? helloSetup : undefined;
35
- },
25
+ import { createWindowApp, definePlugin } from "webloom-framework";
26
+
27
+ const hello = definePlugin({
28
+ id: "hello",
29
+ provides: ["hello.service"],
30
+ setup(ctx) {
31
+ ctx.provide("hello.service", { value: "world" });
36
32
  },
37
- contextExtension: ({ scope }) => ({
38
- // 宿主只读扩展;不能替换 pluginId、unitId 或 instanceId。
39
- scopeKind: scope.identity.kind,
40
- }),
41
33
  });
42
34
 
43
- await host.register({
44
- id: "hello",
45
- name: "Hello",
46
- meta: { defaultEnabled: true, canDisable: true },
47
- units: [{
48
- id: "hello.window",
49
- execution: "window",
50
- lifetime: "root",
51
- provides: ["hello.service"],
52
- }],
35
+ const app = await createWindowApp({ plugins: [hello] });
36
+ const service = app.capability<{ value: string }>("hello.service");
37
+ console.log(service.value); // world
38
+
39
+ await app.dispose();
40
+ ```
41
+
42
+ `createWindowApp()` 会固定创建一个 `window-main` Runtime、生成新的
43
+ `runtimeInstanceId`、装配实现并等待初始插件启动。普通插件不需要手工创建
44
+ Implementation Registry 或调用 `host.register()`;`definePlugin()` 返回的静态
45
+ manifest 不包含 `setup` 函数。
46
+
47
+ ## SharedWorker Runtime
48
+
49
+ Worker 入口只在 Worker realm 中装配插件:
50
+
51
+ ```ts
52
+ // coordinator.worker.ts
53
+ import { definePlugin, startSharedWorkerApp } from "webloom-framework";
54
+
55
+ const coordinator = definePlugin({
56
+ id: "coordinator",
57
+ provides: ["coordinator.service"],
58
+ setup(ctx) {
59
+ ctx.provide("coordinator.service", {
60
+ handle(request: { type: string }) {
61
+ return { type: request.type, instanceId: ctx.instanceId };
62
+ },
63
+ });
64
+ },
53
65
  });
66
+
67
+ startSharedWorkerApp({ id: "coordinator", plugins: [coordinator] });
54
68
  ```
55
69
 
56
- 生产插件必须把 `execution`、`lifetime`、`dependencies`、`provides` `permissions` 写在 `units` 中,并通过 `runtimeUnitImplementationRegistry` 按 `pluginId + unitId` 解析 setup。静态 Manifest 不携带可执行函数。
70
+ Window 侧只连接 Worker,不创建第二套 Worker 插件生命周期:
71
+
72
+ ```ts
73
+ // Vite: this query emits a real, hashed JavaScript SharedWorker chunk.
74
+ // Do not pass the source `.ts` URL to connectSharedWorker in a production build.
75
+ import coordinatorWorkerUrl from "./coordinator.worker.ts?sharedworker&url";
76
+ import { connectSharedWorker } from "webloom-framework";
77
+
78
+ const runtime = await connectSharedWorker({
79
+ id: "coordinator",
80
+ url: coordinatorWorkerUrl,
81
+ });
82
+ const service = runtime.capability("coordinator.service");
83
+ await service.call({ type: "health" });
84
+ ```
85
+
86
+ 句柄统一处理 module `SharedWorker`、握手、完整 baseline、连续 revision、
87
+ 断线和重连。旧代理不会静默换绑到新 Worker;Worker 重启后
88
+ `runtimeInstanceId` 与 `unitInstanceId` 都会变化。
89
+
90
+ Vite 项目必须把 Worker 入口交给 Vite 的 Worker importer(例如
91
+ `?sharedworker&url`),再把构建后导出的 URL 传给框架。框架内部的
92
+ `new SharedWorker(url, { type: "module" })` 只负责运行时连接,不能替调用方的
93
+ Bundler 发现源码 `.ts` 入口。其它 Bundler 应使用等价的独立 SharedWorker
94
+ Rollup entry。仓库的 `pnpm run test:browser` 会先执行生产构建,再从 dist 启动
95
+ 真实浏览器验收。
96
+
97
+ Window 插件依赖 Worker capability 时,把已连接的 `RuntimeHandle` 传给
98
+ `createWindowApp({ remoteRuntime: runtime, plugins })`,并在 setup 中通过
99
+ `ctx.serviceBridge.requireProxy()` 获取精确版本的远程代理。Worker 断线时,Window
100
+ Host 会把相关单元置为 `blocked`;新 baseline 到达后按原启用意图重新协调。
57
101
 
58
102
  ## 公共字段中文语义
59
103
 
60
104
  | 字段 | 中文含义 |
61
105
  | --- | --- |
62
106
  | `pluginId` | 插件产品的稳定标识;用于用户启停和依赖图身份。 |
63
- | `unitId` | 产品在一种执行环境中的稳定运行单元标识。 |
107
+ | `unitId` | 产品在一个 Runtime 中的稳定运行单元标识。 |
64
108
  | `instanceId` | 某运行单元一次启动生成的唯一实例标识;重启不得复用。 |
65
- | `execution` | 运行代码所在环境标签,由宿主定义。 |
66
- | `lifetime` | 实例依附的生命周期标签,由宿主定义。 |
109
+ | `runtime` | 真实 JavaScript 运行空间;v1 仅为 `window-main/shared-worker`。 |
110
+ | `runtimeInstanceId` | 某个 Window 或 SharedWorker 启动生成的不可复用身份。 |
111
+ | `connectionId` | Window 与 SharedWorker 之间一条物理连接的不可复用身份。 |
67
112
  | `scopeId` | 本次生命周期 Scope 的唯一标识。 |
68
113
  | `capability` | 插件提供或依赖的服务契约标识。 |
69
114
  | `contractVersion` | capability 的精确契约版本。 |
70
115
  | `permission` | 字符串形式的权限动作;具体集合由宿主批准。 |
71
116
  | `attributes` | 宿主绑定的只读扩展元数据,不包含私密材料。 |
72
117
  | `desiredEnabled` | 用户或控制面希望产品启用的持久意图。 |
73
- | `state` | 当前运行实例的实际状态,不等于启用意图。 |
118
+ | `state` | 当前 Runtime/运行实例的实际状态,不等于启用意图。 |
74
119
  | `blockedBy` | 实例无法启动时缺失的依赖或 Scope 原因。 |
75
120
 
76
121
  ## 开发与验收
@@ -82,6 +127,8 @@ pnpm typecheck
82
127
  pnpm test
83
128
  pnpm build
84
129
  pnpm run pack:consumer
130
+ # 会安装/校验 Playwright Chromium,再执行生产 dist fixture
131
+ pnpm run test:browser
85
132
  ```
86
133
 
87
134
  `pack:consumer` 会在不访问本仓库源码的临时项目中安装 tarball,分别执行