@lytjs/renderer 6.4.0 → 6.6.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,371 +1,385 @@
1
- # @lytjs/renderer
2
-
3
- > LytJS 渲染后端,提供 DOM 渲染、SSR 渲染、Signal 渲染、Hydration 和 Island Architecture 支持
4
-
5
- ## 安装
6
-
7
- ```bash
8
- npm install @lytjs/renderer
9
- ```
10
-
11
- ## 渲染器类型
12
-
13
- ### DOM 渲染器
14
-
15
- 用于浏览器端的 DOM 渲染
16
-
17
- ```typescript
18
- import { createDOMRenderer } from '@lytjs/renderer';
19
-
20
- const renderer = createDOMRenderer();
21
- renderer.render(vnode, document.getElementById('app'));
22
- ```
23
-
24
- ### Signal 渲染器
25
-
26
- 用于细粒度响应式更新(Vapor 模式)
27
-
28
- ```typescript
29
- import { createSignalRenderer, createVaporRenderer } from '@lytjs/renderer';
30
-
31
- // Signal 渲染器
32
- const signalRenderer = await createSignalRenderer();
33
-
34
- // Vapor 渲染器(Signal 渲染器的别名)
35
- const vaporRenderer = await createVaporRenderer();
36
- ```
37
-
38
- ### SSR 渲染器
39
-
40
- 用于服务端渲染
41
-
42
- ```typescript
43
- import { renderToString, renderToStream } from '@lytjs/renderer';
44
-
45
- // 渲染为字符串
46
- const html = await renderToString(vnode);
47
-
48
- // 流式渲染
49
- const stream = await renderToStream(vnode, {
50
- onChunk: (chunk) => res.write(chunk),
51
- });
52
- ```
53
-
54
- ## 核心 API
55
-
56
- ### createRenderer
57
-
58
- 创建自定义渲染器实例
59
-
60
- ```typescript
61
- import { createRenderer, type RendererOptions } from '@lytjs/renderer';
62
-
63
- const options: RendererOptions = {
64
- createElement: (tag) => document.createElement(tag),
65
- insert: (el, parent, anchor) => parent.insertBefore(el, anchor),
66
- // ...
67
- };
68
-
69
- const renderer = createRenderer(options);
70
- ```
71
-
72
- ### createDOMRenderer
73
-
74
- 创建 DOM 渲染器实例
75
-
76
- ```typescript
77
- import { createDOMRenderer } from '@lytjs/renderer';
78
-
79
- const renderer = createDOMRenderer();
80
- ```
81
-
82
- ### patchProp / patchClass / patchStyle / patchEvent / patchAttr
83
-
84
- DOM 属性更新工具函数
85
-
86
- ```typescript
87
- import {
88
- patchProp,
89
- patchClass,
90
- patchStyle,
91
- patchEvent,
92
- patchAttr,
93
- normalizeEventName,
94
- getEventKey,
95
- parseEventModifier,
96
- createInvoker,
97
- } from '@lytjs/renderer';
98
-
99
- // 更新属性
100
- patchProp(el, 'class', prevValue, nextValue);
101
-
102
- // 更新 class
103
- patchClass(el, 'active visible');
104
-
105
- // 更新 style
106
- patchStyle(el, { color: 'red', fontSize: '14px' });
107
-
108
- // 更新事件
109
- patchEvent(el, 'onClick', prevHandler, nextHandler);
110
- ```
111
-
112
- ## Hydration
113
-
114
- ### createHydrationFunctions
115
-
116
- 创建服务端渲染 Hydration 函数
117
-
118
- ```typescript
119
- import { createHydrationFunctions } from '@lytjs/renderer';
120
-
121
- const { hydrate, hydrateNode } = createHydrationFunctions(options);
122
- ```
123
-
124
- ## Island Architecture
125
-
126
- Island Architecture 用于在 SSR 页面中实现部分区域的客户端交互
127
-
128
- ### hydrateIsland
129
-
130
- 水合单个 Island 组件
131
-
132
- ```typescript
133
- import { hydrateIsland, registerIslandComponent } from '@lytjs/renderer';
134
-
135
- // 注册 Island 组件
136
- await registerIslandComponent('Counter', CounterComponent);
137
-
138
- // 水合 Island
139
- const islandEl = document.querySelector('[data-island="Counter"]');
140
- await hydrateIsland(islandEl, CounterComponent, { initialCount: 0 });
141
- ```
142
-
143
- ### registerIslandComponent
144
-
145
- 注册 Island 组件供后续水合使用
146
-
147
- ```typescript
148
- import { registerIslandComponent } from '@lytjs/renderer';
149
-
150
- await registerIslandComponent('MyComponent', MyComponent);
151
- ```
152
-
153
- ### createIslandSSRContent
154
-
155
- 创建 Island SSR 内容
156
-
157
- ```typescript
158
- import { createIslandSSRContent } from '@lytjs/renderer';
159
-
160
- const html = await createIslandSSRContent(vnode, {
161
- islandId: 'Counter',
162
- });
163
- ```
164
-
165
- ## 懒加载
166
-
167
- 渲染器支持懒加载大型模块,减少初始包体积:
168
-
169
- ```typescript
170
- // SSR 相关函数使用动态导入
171
- import { renderToString, renderToStream } from '@lytjs/renderer';
172
-
173
- // 这些函数会按需加载 SSR 模块
174
- const html = await renderToString(vnode);
175
-
176
- // Signal/Vapor 渲染器也是懒加载的
177
- const signalRenderer = await createSignalRenderer();
178
- ```
179
-
180
- ## 渲染器插件系统
181
-
182
- ### use
183
-
184
- 安装渲染器插件
185
-
186
- ```typescript
187
- import { use, type RendererPlugin } from '@lytjs/renderer';
188
-
189
- const myPlugin: RendererPlugin = {
190
- name: 'MyPlugin',
191
- install(context) {
192
- context.on('beforeMount', (vnode) => {
193
- console.log('Before mount:', vnode);
194
- });
195
- },
196
- beforeMount(vnode) {
197
- console.log('Will mount:', vnode);
198
- },
199
- };
200
-
201
- use(myPlugin);
202
- ```
203
-
204
- ### 插件生命周期钩子
205
-
206
- ```typescript
207
- interface RendererPlugin {
208
- name: string;
209
- install: (context: PluginContext) => void;
210
- beforeMount?: (vnode: VNode) => void;
211
- afterMount?: (vnode: VNode, container: unknown) => void;
212
- beforePatch?: (oldVNode: VNode, newVNode: VNode) => void;
213
- afterPatch?: (vnode: VNode) => void;
214
- beforeUnmount?: (vnode: VNode) => void;
215
- afterUnmount?: (vnode: VNode) => void;
216
- }
217
- ```
218
-
219
- ### 插件管理
220
-
221
- ```typescript
222
- import { use, getInstalledPlugins, isPluginInstalled, removePlugin } from '@lytjs/renderer';
223
-
224
- // 安装插件
225
- use(myPlugin);
226
-
227
- // 检查插件是否已安装
228
- if (isPluginInstalled('MyPlugin')) {
229
- console.log('Plugin is installed');
230
- }
231
-
232
- // 获取所有已安装插件
233
- const plugins = getInstalledPlugins();
234
-
235
- // 移除插件
236
- removePlugin('MyPlugin');
237
- ```
238
-
239
- ## Vapor 模式
240
-
241
- Vapor 模式提供无虚拟 DOM 的细粒度响应式渲染
242
-
243
- ### createVaporApp
244
-
245
- 创建 Vapor 应用
246
-
247
- ```typescript
248
- import { createVaporApp, defineVaporComponent } from '@lytjs/renderer';
249
-
250
- const MyComponent = await defineVaporComponent({
251
- setup() {
252
- const count = signal(0);
253
- return () => html`<div>${count()}</div>`;
254
- },
255
- });
256
-
257
- const app = await createVaporApp(MyComponent);
258
- app.mount('#app');
259
- ```
260
-
261
- ### defineVaporComponent
262
-
263
- 定义 Vapor 组件
264
-
265
- ```typescript
266
- import { defineVaporComponent } from '@lytjs/renderer';
267
-
268
- const Counter = await defineVaporComponent({
269
- props: {
270
- initialCount: { type: Number, default: 0 },
271
- },
272
- setup(props) {
273
- // 组件逻辑
274
- },
275
- });
276
- ```
277
-
278
- ## 组件资源清理
279
-
280
- ```typescript
281
- import {
282
- registerComponentEventListener,
283
- registerComponentEffectSubscription,
284
- registerComponentCleanup,
285
- cleanupComponentResources,
286
- } from '@lytjs/renderer';
287
-
288
- // 注册事件监听器(卸载时自动清理)
289
- registerComponentEventListener(instance, target, 'click', handler);
290
-
291
- // 注册 effect 订阅(卸载时自动清理)
292
- registerComponentEffectSubscription(instance, subscription);
293
-
294
- // 注册自定义清理函数
295
- registerComponentCleanup(instance, () => {
296
- // 清理逻辑
297
- });
298
-
299
- // 手动清理所有资源
300
- cleanupComponentResources(instance);
301
- ```
302
-
303
- ## 首次渲染优化
304
-
305
- ```typescript
306
- import {
307
- withFirstRenderOptimization,
308
- shouldSkipTracking,
309
- getSkippedTrackingCount,
310
- resetSkippedTrackingCount,
311
- } from '@lytjs/renderer';
312
-
313
- // 使用首次渲染优化
314
- withFirstRenderOptimization(() => {
315
- // 首次渲染时跳过不必要的追踪
316
- });
317
-
318
- // 检查是否跳过追踪
319
- if (shouldSkipTracking()) {
320
- console.log('Tracking is skipped');
321
- }
322
- ```
323
-
324
- ## 工具函数
325
-
326
- ```typescript
327
- import { escapeHtml, isBooleanAttr, isVoidElement } from '@lytjs/renderer';
328
-
329
- // HTML 转义
330
- const safe = escapeHtml('<script>alert("xss")</script>');
331
-
332
- // 检查布尔属性
333
- if (isBooleanAttr('disabled')) {
334
- // 处理布尔属性
335
- }
336
-
337
- // 检查自闭合标签
338
- if (isVoidElement('img')) {
339
- // 自闭合标签处理
340
- }
341
- ```
342
-
343
- ## 类型定义
344
-
345
- ```typescript
346
- import type {
347
- VNode,
348
- RendererOptions,
349
- RendererPlugin,
350
- PluginContext,
351
- LifecycleEvent,
352
- DOMRenderer,
353
- SignalRenderer,
354
- VaporRenderer,
355
- VaporApp,
356
- VaporComponentOptions,
357
- HydrationRenderer,
358
- RendererHost,
359
- HostRect,
360
- HostStyleDeclaration,
361
- HostEvent,
362
- HostEventHandler,
363
- } from '@lytjs/renderer';
364
- ```
365
-
366
- ## 相关包
367
-
368
- - [@lytjs/vdom](../vdom) - 虚拟 DOM 实现,渲染器的基础
369
- - [@lytjs/core](../core) - 框架核心入口,整合所有子包
370
- - [@lytjs/adapter-web](../adapter-web) - Web 平台适配器
371
- - [@lytjs/host-contract](../host-contract) - 渲染器宿主抽象
1
+ # @lytjs/renderer
2
+
3
+ > LytJS 渲染后端,提供 DOM 渲染、SSR 渲染、Signal 渲染、Hydration 和 Island Architecture 支持
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @lytjs/renderer
9
+ ```
10
+
11
+ ## 渲染器类型
12
+
13
+ ### DOM 渲染器
14
+
15
+ 用于浏览器端的 DOM 渲染
16
+
17
+ ```typescript
18
+ import { createDOMRenderer } from '@lytjs/renderer';
19
+
20
+ const renderer = createDOMRenderer();
21
+ renderer.render(vnode, document.getElementById('app'));
22
+ ```
23
+
24
+ ### Signal 渲染器
25
+
26
+ 用于细粒度响应式更新(Vapor 模式)
27
+
28
+ ```typescript
29
+ import { createSignalRenderer, createVaporRenderer } from '@lytjs/renderer';
30
+
31
+ // Signal 渲染器
32
+ const signalRenderer = await createSignalRenderer();
33
+
34
+ // Vapor 渲染器(Signal 渲染器的别名)
35
+ const vaporRenderer = await createVaporRenderer();
36
+ ```
37
+
38
+ ### SSR 渲染器
39
+
40
+ 用于服务端渲染
41
+
42
+ ```typescript
43
+ import { renderToString, renderToStream } from '@lytjs/renderer';
44
+
45
+ // 渲染为字符串
46
+ const html = await renderToString(vnode);
47
+
48
+ // 流式渲染
49
+ const stream = await renderToStream(vnode, {
50
+ onChunk: (chunk) => res.write(chunk),
51
+ });
52
+ ```
53
+
54
+ ## 核心 API
55
+
56
+ ### createRenderer
57
+
58
+ 创建自定义渲染器实例
59
+
60
+ ```typescript
61
+ import { createRenderer, type RendererOptions } from '@lytjs/renderer';
62
+
63
+ const options: RendererOptions = {
64
+ createElement: (tag) => document.createElement(tag),
65
+ insert: (el, parent, anchor) => parent.insertBefore(el, anchor),
66
+ // ...
67
+ };
68
+
69
+ const renderer = createRenderer(options);
70
+ ```
71
+
72
+ ### createDOMRenderer
73
+
74
+ 创建 DOM 渲染器实例
75
+
76
+ ```typescript
77
+ import { createDOMRenderer } from '@lytjs/renderer';
78
+
79
+ const renderer = createDOMRenderer();
80
+ ```
81
+
82
+ ### patchProp / patchClass / patchStyle / patchEvent / patchAttr
83
+
84
+ DOM 属性更新工具函数
85
+
86
+ ```typescript
87
+ import {
88
+ patchProp,
89
+ patchClass,
90
+ patchStyle,
91
+ patchEvent,
92
+ patchAttr,
93
+ normalizeEventName,
94
+ getEventKey,
95
+ parseEventModifier,
96
+ createInvoker,
97
+ } from '@lytjs/renderer';
98
+
99
+ // 更新属性
100
+ patchProp(el, 'class', prevValue, nextValue);
101
+
102
+ // 更新 class
103
+ patchClass(el, 'active visible');
104
+
105
+ // 更新 style
106
+ patchStyle(el, { color: 'red', fontSize: '14px' });
107
+
108
+ // 更新事件
109
+ patchEvent(el, 'onClick', prevHandler, nextHandler);
110
+ ```
111
+
112
+ ## Hydration
113
+
114
+ ### createHydrationFunctions
115
+
116
+ 创建服务端渲染 Hydration 函数
117
+
118
+ ```typescript
119
+ import { createHydrationFunctions } from '@lytjs/renderer';
120
+
121
+ const { hydrate, hydrateNode } = createHydrationFunctions(options);
122
+ ```
123
+
124
+ ## Island Architecture
125
+
126
+ Island Architecture 用于在 SSR 页面中实现部分区域的客户端交互
127
+
128
+ ### hydrateIsland
129
+
130
+ 水合单个 Island 组件
131
+
132
+ ```typescript
133
+ import { hydrateIsland, registerIslandComponent } from '@lytjs/renderer';
134
+
135
+ // 注册 Island 组件
136
+ await registerIslandComponent('Counter', CounterComponent);
137
+
138
+ // 水合 Island
139
+ const islandEl = document.querySelector('[data-island="Counter"]');
140
+ await hydrateIsland(islandEl, CounterComponent, { initialCount: 0 });
141
+ ```
142
+
143
+ ### registerIslandComponent
144
+
145
+ 注册 Island 组件供后续水合使用
146
+
147
+ ```typescript
148
+ import { registerIslandComponent } from '@lytjs/renderer';
149
+
150
+ await registerIslandComponent('MyComponent', MyComponent);
151
+ ```
152
+
153
+ ### createIslandSSRContent
154
+
155
+ 创建 Island SSR 内容
156
+
157
+ ```typescript
158
+ import { createIslandSSRContent } from '@lytjs/renderer';
159
+
160
+ const html = await createIslandSSRContent(vnode, {
161
+ islandId: 'Counter',
162
+ });
163
+ ```
164
+
165
+ ## 懒加载
166
+
167
+ 渲染器支持懒加载大型模块,减少初始包体积:
168
+
169
+ ```typescript
170
+ // SSR 相关函数使用动态导入
171
+ import { renderToString, renderToStream } from '@lytjs/renderer';
172
+
173
+ // 这些函数会按需加载 SSR 模块
174
+ const html = await renderToString(vnode);
175
+
176
+ // Signal/Vapor 渲染器也是懒加载的
177
+ const signalRenderer = await createSignalRenderer();
178
+ ```
179
+
180
+ ## 渲染器插件系统
181
+
182
+ ### use
183
+
184
+ 安装渲染器插件
185
+
186
+ ```typescript
187
+ import { use, type RendererPlugin } from '@lytjs/renderer';
188
+
189
+ const myPlugin: RendererPlugin = {
190
+ name: 'MyPlugin',
191
+ install(context) {
192
+ context.on('beforeMount', (vnode) => {
193
+ console.log('Before mount:', vnode);
194
+ });
195
+ },
196
+ beforeMount(vnode) {
197
+ console.log('Will mount:', vnode);
198
+ },
199
+ };
200
+
201
+ use(myPlugin);
202
+ ```
203
+
204
+ ### 插件生命周期钩子
205
+
206
+ ```typescript
207
+ interface RendererPlugin {
208
+ name: string;
209
+ install: (context: PluginContext) => void;
210
+ beforeMount?: (vnode: VNode) => void;
211
+ afterMount?: (vnode: VNode, container: unknown) => void;
212
+ beforePatch?: (oldVNode: VNode, newVNode: VNode) => void;
213
+ afterPatch?: (vnode: VNode) => void;
214
+ beforeUnmount?: (vnode: VNode) => void;
215
+ afterUnmount?: (vnode: VNode) => void;
216
+ }
217
+ ```
218
+
219
+ ### 插件管理
220
+
221
+ ```typescript
222
+ import { use, getInstalledPlugins, isPluginInstalled, removePlugin } from '@lytjs/renderer';
223
+
224
+ // 安装插件
225
+ use(myPlugin);
226
+
227
+ // 检查插件是否已安装
228
+ if (isPluginInstalled('MyPlugin')) {
229
+ console.log('Plugin is installed');
230
+ }
231
+
232
+ // 获取所有已安装插件
233
+ const plugins = getInstalledPlugins();
234
+
235
+ // 移除插件
236
+ removePlugin('MyPlugin');
237
+ ```
238
+
239
+ ## Vapor 模式
240
+
241
+ Vapor 模式提供无虚拟 DOM 的细粒度响应式渲染
242
+
243
+ ### createVaporApp
244
+
245
+ 创建 Vapor 应用
246
+
247
+ ```typescript
248
+ import { createVaporApp, defineVaporComponent } from '@lytjs/renderer';
249
+
250
+ const MyComponent = await defineVaporComponent({
251
+ setup() {
252
+ const count = signal(0);
253
+ return () => html`<div>${count()}</div>`;
254
+ },
255
+ });
256
+
257
+ const app = await createVaporApp(MyComponent);
258
+ app.mount('#app');
259
+ ```
260
+
261
+ ### defineVaporComponent
262
+
263
+ 定义 Vapor 组件
264
+
265
+ ```typescript
266
+ import { defineVaporComponent } from '@lytjs/renderer';
267
+
268
+ const Counter = await defineVaporComponent({
269
+ props: {
270
+ initialCount: { type: Number, default: 0 },
271
+ },
272
+ setup(props) {
273
+ // 组件逻辑
274
+ },
275
+ });
276
+ ```
277
+
278
+ ## 组件资源清理
279
+
280
+ ```typescript
281
+ import {
282
+ registerComponentEventListener,
283
+ registerComponentEffectSubscription,
284
+ registerComponentCleanup,
285
+ cleanupComponentResources,
286
+ } from '@lytjs/renderer';
287
+
288
+ // 注册事件监听器(卸载时自动清理)
289
+ registerComponentEventListener(instance, target, 'click', handler);
290
+
291
+ // 注册 effect 订阅(卸载时自动清理)
292
+ registerComponentEffectSubscription(instance, subscription);
293
+
294
+ // 注册自定义清理函数
295
+ registerComponentCleanup(instance, () => {
296
+ // 清理逻辑
297
+ });
298
+
299
+ // 手动清理所有资源
300
+ cleanupComponentResources(instance);
301
+ ```
302
+
303
+ ## 首次渲染优化
304
+
305
+ ```typescript
306
+ import {
307
+ withFirstRenderOptimization,
308
+ shouldSkipTracking,
309
+ getSkippedTrackingCount,
310
+ resetSkippedTrackingCount,
311
+ } from '@lytjs/renderer';
312
+
313
+ // 使用首次渲染优化
314
+ withFirstRenderOptimization(() => {
315
+ // 首次渲染时跳过不必要的追踪
316
+ });
317
+
318
+ // 检查是否跳过追踪
319
+ if (shouldSkipTracking()) {
320
+ console.log('Tracking is skipped');
321
+ }
322
+ ```
323
+
324
+ ## 工具函数
325
+
326
+ ```typescript
327
+ import { escapeHtml, isBooleanAttr, isVoidElement } from '@lytjs/renderer';
328
+
329
+ // HTML 转义
330
+ const safe = escapeHtml('<script>alert("xss")</script>');
331
+
332
+ // 检查布尔属性
333
+ if (isBooleanAttr('disabled')) {
334
+ // 处理布尔属性
335
+ }
336
+
337
+ // 检查自闭合标签
338
+ if (isVoidElement('img')) {
339
+ // 自闭合标签处理
340
+ }
341
+ ```
342
+
343
+ ## 类型定义
344
+
345
+ ```typescript
346
+ import type {
347
+ VNode,
348
+ RendererOptions,
349
+ RendererPlugin,
350
+ PluginContext,
351
+ LifecycleEvent,
352
+ DOMRenderer,
353
+ SignalRenderer,
354
+ VaporRenderer,
355
+ VaporApp,
356
+ VaporComponentOptions,
357
+ HydrationRenderer,
358
+ RendererHost,
359
+ HostRect,
360
+ HostStyleDeclaration,
361
+ HostEvent,
362
+ HostEventHandler,
363
+ } from '@lytjs/renderer';
364
+ ```
365
+
366
+ ## 相关包
367
+
368
+ - [@lytjs/vdom](../vdom) - 虚拟 DOM 实现,渲染器的基础
369
+ - [@lytjs/core](../core) - 框架核心入口,整合所有子包
370
+ - [@lytjs/adapter-web](../adapter-web) - Web 平台适配器
371
+ - [@lytjs/host-contract](../host-contract) - 渲染器宿主抽象
372
+
373
+ ## 依赖版本
374
+
375
+ - [@lytjs/reactivity](https://www.npmjs.com/package/@lytjs/reactivity): ^6.4.0
376
+ - [@lytjs/vdom](https://www.npmjs.com/package/@lytjs/vdom): ^6.4.0
377
+ - [@lytjs/common-is](https://www.npmjs.com/package/@lytjs/common-is): ^6.4.0
378
+ - [@lytjs/common-string](https://www.npmjs.com/package/@lytjs/common-string): ^6.4.0
379
+ - [@lytjs/common-events](https://www.npmjs.com/package/@lytjs/common-events): ^6.4.0
380
+ - [@lytjs/common-dom](https://www.npmjs.com/package/@lytjs/common-dom): ^6.4.0
381
+ - [@lytjs/common-error](https://www.npmjs.com/package/@lytjs/common-error): ^6.4.0
382
+ - [@lytjs/dom-runtime](https://www.npmjs.com/package/@lytjs/dom-runtime): ^6.4.0
383
+ - [@lytjs/compiler](https://www.npmjs.com/package/@lytjs/compiler): ^6.4.0
384
+ - [@lytjs/host-contract](https://www.npmjs.com/package/@lytjs/host-contract): ^6.4.0
385
+ - [@lytjs/adapter-web](https://www.npmjs.com/package/@lytjs/adapter-web): ^6.4.0