@lytjs/ssr 6.8.0 → 6.9.1
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/dist/index.d.cts +612 -0
- package/dist/index.d.ts +612 -0
- package/package.json +1 -1
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
import { VNode } from '@lytjs/vdom';
|
|
2
|
+
import * as _lytjs_component from '@lytjs/component';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @lytjs/ssr - 服务端渲染
|
|
6
|
+
*
|
|
7
|
+
* 将 VNode 渲染为 HTML 字符串
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 渲染 VNode 为 HTML 字符串
|
|
12
|
+
*/
|
|
13
|
+
declare function renderToString(vnode: VNode | VNode[] | string | number | null | undefined): string;
|
|
14
|
+
/**
|
|
15
|
+
* 渲染完整的 HTML 页面
|
|
16
|
+
*/
|
|
17
|
+
declare function renderToHtml(vnode: VNode | VNode[], options?: {
|
|
18
|
+
title?: string;
|
|
19
|
+
lang?: string;
|
|
20
|
+
head?: string;
|
|
21
|
+
bodyAttrs?: Record<string, string>;
|
|
22
|
+
}): string;
|
|
23
|
+
declare const _default: {
|
|
24
|
+
renderToString: typeof renderToString;
|
|
25
|
+
renderToHtml: typeof renderToHtml;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @lytjs/ssr - 虚拟列表组件
|
|
30
|
+
*
|
|
31
|
+
* 高性能大数据列表渲染
|
|
32
|
+
*/
|
|
33
|
+
declare const VirtualList: _lytjs_component.ComponentOptions<Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @lytjs/ssr - 流式服务端渲染
|
|
37
|
+
*
|
|
38
|
+
* 将 VNode 渲染为 ReadableStream,支持分块发送和 Suspense 边界
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** 流式渲染配置选项 */
|
|
42
|
+
interface StreamRenderOptions {
|
|
43
|
+
/** 每个分块的最大字节数,默认 4096 */
|
|
44
|
+
chunkSize?: number;
|
|
45
|
+
/** Shell 就绪回调(Suspense 边界之前的初始内容已发送) */
|
|
46
|
+
onShellReady?: () => void;
|
|
47
|
+
/** 错误回调 */
|
|
48
|
+
onError?: (error: Error) => void;
|
|
49
|
+
/** 流式渲染超时时间(毫秒),默认 30000 */
|
|
50
|
+
timeout?: number;
|
|
51
|
+
/** 当渲染超时时的回退 HTML 内容 */
|
|
52
|
+
fallbackHtml?: string;
|
|
53
|
+
/** 流控制:每秒最大字节数,用于防止突发流量 */
|
|
54
|
+
maxBytesPerSecond?: number;
|
|
55
|
+
/** 是否启用错误恢复模式,默认 true */
|
|
56
|
+
errorRecovery?: boolean;
|
|
57
|
+
/** 单个组件渲染超时(毫秒),默认 5000 */
|
|
58
|
+
componentTimeout?: number;
|
|
59
|
+
}
|
|
60
|
+
/** 异步数据预取上下文 */
|
|
61
|
+
interface DataPrefetchContext {
|
|
62
|
+
/** 路由路径 */
|
|
63
|
+
path?: string;
|
|
64
|
+
/** 路由参数 */
|
|
65
|
+
params?: Record<string, string>;
|
|
66
|
+
/** 查询参数 */
|
|
67
|
+
query?: Record<string, string>;
|
|
68
|
+
}
|
|
69
|
+
/** 异步数据预取结果 */
|
|
70
|
+
interface PrefetchResult {
|
|
71
|
+
/** 预取的数据 */
|
|
72
|
+
data: Record<string, unknown>;
|
|
73
|
+
/** 数据过期时间(毫秒) */
|
|
74
|
+
ttl?: number;
|
|
75
|
+
}
|
|
76
|
+
/** 支持数据预取的组件接口 */
|
|
77
|
+
interface PrefetchableComponent {
|
|
78
|
+
/** 预取数据方法 */
|
|
79
|
+
prefetch?: (context: DataPrefetchContext) => Promise<PrefetchResult>;
|
|
80
|
+
}
|
|
81
|
+
/** 流式渲染增强选项 */
|
|
82
|
+
interface EnhancedStreamRenderOptions extends StreamRenderOptions {
|
|
83
|
+
/** 数据预取上下文 */
|
|
84
|
+
prefetchContext?: DataPrefetchContext;
|
|
85
|
+
/** 数据预取完成回调 */
|
|
86
|
+
onDataPrefetched?: (data: Record<string, unknown>) => void;
|
|
87
|
+
/** 是否启用渐进式水合 */
|
|
88
|
+
progressiveHydration?: boolean;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 将 VNode 渲染为 ReadableStream(流式服务端渲染)
|
|
92
|
+
*
|
|
93
|
+
* @description
|
|
94
|
+
* 将 VNode 树渲染为 HTML 并通过 ReadableStream 分块发送。
|
|
95
|
+
* 支持以下特性:
|
|
96
|
+
* - 按组件边界拆分 HTML 分块
|
|
97
|
+
* - 支持 Suspense 边界(先发送 shell,再发送异步内容)
|
|
98
|
+
* - 使用 TextEncoder 编码为 Uint8Array
|
|
99
|
+
* - 可配置分块大小和回调
|
|
100
|
+
* - 超时控制和错误恢复
|
|
101
|
+
* - 流速率控制
|
|
102
|
+
*
|
|
103
|
+
* @param vnode - 要渲染的 VNode
|
|
104
|
+
* @param options - 流式渲染配置选项
|
|
105
|
+
* @returns ReadableStream<Uint8Array>
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const stream = renderToStream(vnode, {
|
|
110
|
+
* chunkSize: 2048,
|
|
111
|
+
* onShellReady: () => console.log('Shell 已发送'),
|
|
112
|
+
* onError: (err) => console.error(err),
|
|
113
|
+
* timeout: 30000,
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* for await (const chunk of stream) {
|
|
117
|
+
* response.write(chunk);
|
|
118
|
+
* }
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
declare function renderToStream(vnode: VNode, options?: StreamRenderOptions): ReadableStream<Uint8Array>;
|
|
122
|
+
/**
|
|
123
|
+
* 将 VNode 渲染为异步 ReadableStream(支持异步组件和数据预取)
|
|
124
|
+
*
|
|
125
|
+
* @description
|
|
126
|
+
* 与 renderToStream 类似,但支持异步组件和数据预取。
|
|
127
|
+
* 遇到返回 Promise 的组件时先发送占位内容,等 Promise 解析后再发送实际内容。
|
|
128
|
+
*
|
|
129
|
+
* @param vnode - 要渲染的 VNode
|
|
130
|
+
* @param options - 流式渲染配置选项
|
|
131
|
+
* @returns ReadableStream<Uint8Array>
|
|
132
|
+
*/
|
|
133
|
+
declare function renderToStreamAsync(vnode: VNode, options?: EnhancedStreamRenderOptions): ReadableStream<Uint8Array>;
|
|
134
|
+
/**
|
|
135
|
+
* 增强型流式渲染(包含数据预取和渐进式水合)
|
|
136
|
+
*
|
|
137
|
+
* @description
|
|
138
|
+
* 完整的流式渲染解决方案,包含数据预取、渐进式水合等高级特性。
|
|
139
|
+
*
|
|
140
|
+
* @param vnode - 要渲染的 VNode
|
|
141
|
+
* @param options - 增强型流式渲染配置
|
|
142
|
+
* @returns Promise<{ stream: ReadableStream<Uint8Array>; dehydratedState: Record<string, any> }>
|
|
143
|
+
*/
|
|
144
|
+
declare function renderToStreamEnhanced(vnode: VNode, options?: EnhancedStreamRenderOptions): Promise<{
|
|
145
|
+
stream: ReadableStream<Uint8Array>;
|
|
146
|
+
dehydratedState: Record<string, unknown>;
|
|
147
|
+
}>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @lytjs/ssr - 静态站点生成(SSG)
|
|
151
|
+
*
|
|
152
|
+
* 预渲染页面配置为静态 HTML 文件
|
|
153
|
+
*/
|
|
154
|
+
|
|
155
|
+
/** SSG 页面配置 */
|
|
156
|
+
interface SSGPage {
|
|
157
|
+
/** 页面路径,如 '/' 或 '/about' */
|
|
158
|
+
path: string;
|
|
159
|
+
/** 页面组件 VNode */
|
|
160
|
+
component: VNode;
|
|
161
|
+
/** 可选布局组件 */
|
|
162
|
+
layout?: VNode;
|
|
163
|
+
/** 页面头部信息 */
|
|
164
|
+
head?: {
|
|
165
|
+
/** 页面标题 */
|
|
166
|
+
title?: string;
|
|
167
|
+
/** 元信息键值对 */
|
|
168
|
+
meta?: Record<string, string>;
|
|
169
|
+
};
|
|
170
|
+
/** 额外的脚本标签 */
|
|
171
|
+
scripts?: string[];
|
|
172
|
+
/** 额外的样式标签 */
|
|
173
|
+
styles?: string[];
|
|
174
|
+
}
|
|
175
|
+
/** SSG 生成选项 */
|
|
176
|
+
interface SSGOptions {
|
|
177
|
+
/** 站点基础 URL,默认 '/' */
|
|
178
|
+
baseUrl?: string;
|
|
179
|
+
/** 输出目录,默认 'dist' */
|
|
180
|
+
outDir?: string;
|
|
181
|
+
/** 默认页面标题 */
|
|
182
|
+
defaultTitle?: string;
|
|
183
|
+
/** 默认语言 */
|
|
184
|
+
lang?: string;
|
|
185
|
+
/** 是否生成 sitemap */
|
|
186
|
+
generateSitemap?: boolean;
|
|
187
|
+
/** 站点名称(用于 sitemap) */
|
|
188
|
+
siteName?: string;
|
|
189
|
+
/** 是否使用哈希路由 */
|
|
190
|
+
hashMode?: boolean;
|
|
191
|
+
/** 全局额外脚本 */
|
|
192
|
+
globalScripts?: string[];
|
|
193
|
+
/** 全局额外样式 */
|
|
194
|
+
globalStyles?: string[];
|
|
195
|
+
/** ISR 配置(增量静态再生成) */
|
|
196
|
+
isr?: {
|
|
197
|
+
/** 重新验证间隔(秒),0 表示按需重新验证 */
|
|
198
|
+
revalidate?: number;
|
|
199
|
+
/** 是否启用增量静态再生成 */
|
|
200
|
+
enabled?: boolean;
|
|
201
|
+
/** 预渲染 fallback 页面 */
|
|
202
|
+
fallback?: 'blocking' | boolean;
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 将生成的 HTML 写入文件系统
|
|
207
|
+
*
|
|
208
|
+
* @description
|
|
209
|
+
* 将 generateStaticPages 生成的结果写入到指定的输出目录。
|
|
210
|
+
* 会自动创建所需的目录结构。
|
|
211
|
+
*
|
|
212
|
+
* @param pages - 页面配置数组
|
|
213
|
+
* @param options - SSG 选项
|
|
214
|
+
* @returns Promise<void>
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* await writeStaticFiles(pages, { outDir: 'build' });
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
declare function writeStaticFiles(pages: SSGPage[], options?: SSGOptions): Promise<void>;
|
|
222
|
+
/**
|
|
223
|
+
* 预渲染页面配置数组为静态 HTML
|
|
224
|
+
*
|
|
225
|
+
* @description
|
|
226
|
+
* 接受页面配置数组,为每个页面生成完整的 HTML 内容。
|
|
227
|
+
* 返回一个 Map,键为文件路径,值为 HTML 内容。
|
|
228
|
+
*
|
|
229
|
+
* @param pages - 页面配置数组
|
|
230
|
+
* @param options - SSG 生成选项
|
|
231
|
+
* @returns Map<string, string> 文件路径 -> HTML 内容
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* const pages: SSGPage[] = [
|
|
236
|
+
* {
|
|
237
|
+
* path: '/',
|
|
238
|
+
* component: h('div', {}, 'Home'),
|
|
239
|
+
* head: { title: '首页', meta: { description: '欢迎' } },
|
|
240
|
+
* },
|
|
241
|
+
* {
|
|
242
|
+
* path: '/about',
|
|
243
|
+
* component: h('div', {}, 'About'),
|
|
244
|
+
* },
|
|
245
|
+
* ];
|
|
246
|
+
*
|
|
247
|
+
* const results = generateStaticPages(pages, {
|
|
248
|
+
* baseUrl: 'https://example.com',
|
|
249
|
+
* defaultTitle: 'My Site',
|
|
250
|
+
* });
|
|
251
|
+
*
|
|
252
|
+
* for (const [filePath, html] of results) {
|
|
253
|
+
* console.log(filePath, html);
|
|
254
|
+
* }
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
declare function generateStaticPages(pages: SSGPage[], options?: SSGOptions): Map<string, string>;
|
|
258
|
+
/**
|
|
259
|
+
* 生成页面路由清单
|
|
260
|
+
*
|
|
261
|
+
* @description
|
|
262
|
+
* 根据页面配置生成一个 JSON 格式的路由清单,
|
|
263
|
+
* 可用于客户端路由注册或构建分析。
|
|
264
|
+
*
|
|
265
|
+
* @param pages - 页面配置数组
|
|
266
|
+
* @param baseUrl - 站点基础 URL
|
|
267
|
+
* @returns 路由信息数组
|
|
268
|
+
*/
|
|
269
|
+
declare function generateRouteManifest(pages: SSGPage[], baseUrl?: string): Array<{
|
|
270
|
+
path: string;
|
|
271
|
+
filePath: string;
|
|
272
|
+
title?: string;
|
|
273
|
+
}>;
|
|
274
|
+
/**
|
|
275
|
+
* 验证页面配置数组的合法性
|
|
276
|
+
*
|
|
277
|
+
* @description
|
|
278
|
+
* 检查每个页面配置是否包含必要的字段(path 和 component),
|
|
279
|
+
* 以及路径是否合法。返回错误信息数组。
|
|
280
|
+
*
|
|
281
|
+
* @param pages - 页面配置数组
|
|
282
|
+
* @returns 错误信息数组,空数组表示全部合法
|
|
283
|
+
*/
|
|
284
|
+
declare function validatePages(pages: SSGPage[]): string[];
|
|
285
|
+
/**
|
|
286
|
+
* 创建 ISR 中间件
|
|
287
|
+
*
|
|
288
|
+
* @description
|
|
289
|
+
* 创建用于 Express/Fastify 等框架的 ISR 中间件,
|
|
290
|
+
* 支持增量静态再生成和背景重新验证。
|
|
291
|
+
*
|
|
292
|
+
* @param options - ISR 选项
|
|
293
|
+
* @returns 中间件函数
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* import express from 'express';
|
|
298
|
+
* import { createISRMiddleware, generateStaticPages } from '@lytjs/ssr';
|
|
299
|
+
*
|
|
300
|
+
* const app = express();
|
|
301
|
+
*
|
|
302
|
+
* // 预生成的页面
|
|
303
|
+
* const pages = [
|
|
304
|
+
* { path: '/', component: homeComponent },
|
|
305
|
+
* ];
|
|
306
|
+
*
|
|
307
|
+
* const staticPages = generateStaticPages(pages);
|
|
308
|
+
*
|
|
309
|
+
* app.use(createISRMiddleware({
|
|
310
|
+
* staticPages,
|
|
311
|
+
* revalidate: 60, // 60秒后重新验证
|
|
312
|
+
* async regenerate(path) {
|
|
313
|
+
* const page = pages.find(p => p.path === path);
|
|
314
|
+
* if (page) {
|
|
315
|
+
* return generateStaticPages([page]).get('/index.html')!;
|
|
316
|
+
* }
|
|
317
|
+
* throw new Error('Page not found');
|
|
318
|
+
* }
|
|
319
|
+
* }));
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
declare function createISRMiddleware(options: {
|
|
323
|
+
/** 预生成的静态页面 */
|
|
324
|
+
staticPages: Map<string, string>;
|
|
325
|
+
/** 重新验证间隔(秒) */
|
|
326
|
+
revalidate?: number;
|
|
327
|
+
/** 是否启用 ISR */
|
|
328
|
+
enabled?: boolean;
|
|
329
|
+
/** 重新生成页面的函数 */
|
|
330
|
+
regenerate?: (path: string) => Promise<string>;
|
|
331
|
+
}): (req: any, res: any, next: any) => Promise<any>;
|
|
332
|
+
/**
|
|
333
|
+
* 触发按需重新验证
|
|
334
|
+
*
|
|
335
|
+
* @description
|
|
336
|
+
* 手动触发特定路径的重新验证,适合于内容更新后调用。
|
|
337
|
+
*
|
|
338
|
+
* @param path - 要重新验证的路径
|
|
339
|
+
* @param regenerate - 重新生成页面的函数
|
|
340
|
+
* @returns Promise<string> 新生成的 HTML
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* ```typescript
|
|
344
|
+
* // 当博客文章更新时
|
|
345
|
+
* await revalidateOnDemand(
|
|
346
|
+
* '/blog/my-post',
|
|
347
|
+
* async () => generatePostHTML('my-post')
|
|
348
|
+
* );
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
declare function revalidateOnDemand(path: string, regenerate: () => Promise<string>): Promise<string>;
|
|
352
|
+
/**
|
|
353
|
+
* 获取 ISR 缓存统计信息
|
|
354
|
+
*
|
|
355
|
+
* @description
|
|
356
|
+
* 获取当前 ISR 缓存的统计信息,用于监控和调试。
|
|
357
|
+
*
|
|
358
|
+
* @returns 缓存统计信息
|
|
359
|
+
*/
|
|
360
|
+
declare function getISRCacheStats(): {
|
|
361
|
+
total: number;
|
|
362
|
+
paths: string[];
|
|
363
|
+
};
|
|
364
|
+
/**
|
|
365
|
+
* 清除 ISR 缓存
|
|
366
|
+
*
|
|
367
|
+
* @description
|
|
368
|
+
* 清除指定路径或所有过期的缓存。
|
|
369
|
+
*
|
|
370
|
+
* @param path - 可选,要清除的特定路径
|
|
371
|
+
* @param maxAge - 可选,清除超过指定秒数的缓存
|
|
372
|
+
*/
|
|
373
|
+
declare function clearISRCache(path?: string, maxAge?: number): void;
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* @lytjs/ssr - 服务端组件完善
|
|
377
|
+
*
|
|
378
|
+
* 提供服务端组件生命周期管理、数据预取优化、状态序列化等功能
|
|
379
|
+
*/
|
|
380
|
+
|
|
381
|
+
/** 服务端组件生命周期钩子类型 */
|
|
382
|
+
type ServerLifecycleHook = (context: ServerComponentContext) => Promise<void> | void;
|
|
383
|
+
/** 服务端组件上下文 */
|
|
384
|
+
interface ServerComponentContext {
|
|
385
|
+
/** 组件唯一 ID */
|
|
386
|
+
componentId: string;
|
|
387
|
+
/** 路由信息 */
|
|
388
|
+
route?: {
|
|
389
|
+
path: string;
|
|
390
|
+
params: Record<string, string>;
|
|
391
|
+
query: Record<string, string>;
|
|
392
|
+
};
|
|
393
|
+
/** 请求上下文 */
|
|
394
|
+
request?: {
|
|
395
|
+
headers: Record<string, string | undefined>;
|
|
396
|
+
cookies: Record<string, string>;
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/** 服务端组件注册信息 */
|
|
400
|
+
interface ServerComponentRegistration {
|
|
401
|
+
/** 组件名称 */
|
|
402
|
+
name: string;
|
|
403
|
+
/** 组件渲染函数 */
|
|
404
|
+
render: () => VNode;
|
|
405
|
+
/** 服务端初始化钩子 */
|
|
406
|
+
onServerInit?: ServerLifecycleHook;
|
|
407
|
+
/** 数据预取钩子 */
|
|
408
|
+
prefetch?: (context: DataPrefetchContext) => Promise<PrefetchResult>;
|
|
409
|
+
/** 服务端清理钩子 */
|
|
410
|
+
onServerCleanup?: ServerLifecycleHook;
|
|
411
|
+
}
|
|
412
|
+
/** 服务端组件状态管理器 */
|
|
413
|
+
declare class ServerComponentStateManager {
|
|
414
|
+
/** 注册的组件 */
|
|
415
|
+
private registrations;
|
|
416
|
+
/** 正在执行的预取请求 */
|
|
417
|
+
private pendingPrefetches;
|
|
418
|
+
/** 组件初始化状态 */
|
|
419
|
+
private initializationStates;
|
|
420
|
+
/**
|
|
421
|
+
* 注册服务端组件
|
|
422
|
+
*/
|
|
423
|
+
register(name: string, registration: ServerComponentRegistration): void;
|
|
424
|
+
/**
|
|
425
|
+
* 取消注册服务端组件
|
|
426
|
+
*/
|
|
427
|
+
unregister(name: string): void;
|
|
428
|
+
/**
|
|
429
|
+
* 获取已注册的组件
|
|
430
|
+
*/
|
|
431
|
+
getRegistration(name: string): ServerComponentRegistration | undefined;
|
|
432
|
+
/**
|
|
433
|
+
* 初始化服务端组件
|
|
434
|
+
*/
|
|
435
|
+
initializeComponent(name: string, context: ServerComponentContext): Promise<void>;
|
|
436
|
+
/**
|
|
437
|
+
* 清理服务端组件
|
|
438
|
+
*/
|
|
439
|
+
cleanupComponent(name: string, context: ServerComponentContext): Promise<void>;
|
|
440
|
+
/**
|
|
441
|
+
* 预取组件数据(带缓存)
|
|
442
|
+
*/
|
|
443
|
+
prefetchComponentData(name: string, context: DataPrefetchContext, cacheKey?: string): Promise<PrefetchResult>;
|
|
444
|
+
/**
|
|
445
|
+
* 清除所有缓存
|
|
446
|
+
*/
|
|
447
|
+
clearAll(): void;
|
|
448
|
+
}
|
|
449
|
+
/** 全局状态管理器实例 */
|
|
450
|
+
declare const stateManager: ServerComponentStateManager;
|
|
451
|
+
/**
|
|
452
|
+
* 注册服务端组件
|
|
453
|
+
*/
|
|
454
|
+
declare function registerServerComponent(name: string, registration: ServerComponentRegistration): void;
|
|
455
|
+
/**
|
|
456
|
+
* 取消注册服务端组件
|
|
457
|
+
*/
|
|
458
|
+
declare function unregisterServerComponent(name: string): void;
|
|
459
|
+
/**
|
|
460
|
+
* 从 VNode 树中收集需要预取数据的组件
|
|
461
|
+
*/
|
|
462
|
+
declare function collectPrefetchComponents(vnode: VNode | VNode[] | string | number | null | undefined): string[];
|
|
463
|
+
/**
|
|
464
|
+
* 并发预取多个组件的数据
|
|
465
|
+
*/
|
|
466
|
+
declare function prefetchAllComponents(components: string[], context: DataPrefetchContext): Promise<Record<string, PrefetchResult>>;
|
|
467
|
+
/**
|
|
468
|
+
* 安全的状态序列化
|
|
469
|
+
* 处理循环引用、日期、正则表达式等特殊类型
|
|
470
|
+
*/
|
|
471
|
+
declare function safeSerializeState(state: unknown): string;
|
|
472
|
+
/**
|
|
473
|
+
* 安全的状态反序列化
|
|
474
|
+
* 恢复特殊类型
|
|
475
|
+
*/
|
|
476
|
+
declare function safeDeserializeState(serialized: string): unknown;
|
|
477
|
+
/**
|
|
478
|
+
* 创建组件脱水状态
|
|
479
|
+
*/
|
|
480
|
+
interface ComponentDehydratedState {
|
|
481
|
+
/** 组件名称 */
|
|
482
|
+
componentName: string;
|
|
483
|
+
/** 组件 Props */
|
|
484
|
+
props: Record<string, unknown>;
|
|
485
|
+
/** 预取的数据 */
|
|
486
|
+
data?: Record<string, unknown>;
|
|
487
|
+
/** 错误信息 */
|
|
488
|
+
error?: string;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* 构建完整的脱水状态
|
|
492
|
+
*/
|
|
493
|
+
declare function buildDehydratedState(prefetchResults: Record<string, PrefetchResult>): Record<string, ComponentDehydratedState>;
|
|
494
|
+
/**
|
|
495
|
+
* 服务端组件管理器装饰器
|
|
496
|
+
*/
|
|
497
|
+
declare function ServerComponent(options: {
|
|
498
|
+
name: string;
|
|
499
|
+
prefetch?: (context: DataPrefetchContext) => Promise<PrefetchResult>;
|
|
500
|
+
onInit?: ServerLifecycleHook;
|
|
501
|
+
onCleanup?: ServerLifecycleHook;
|
|
502
|
+
}): (target: {
|
|
503
|
+
name?: string;
|
|
504
|
+
render?: () => VNode;
|
|
505
|
+
}) => void;
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* @lytjs/ssr - 组件级水合提示
|
|
509
|
+
*
|
|
510
|
+
* 提供水合标记、策略检测和状态序列化等辅助函数,
|
|
511
|
+
* 用于 SSR 输出中嵌入客户端水合所需的信息
|
|
512
|
+
*/
|
|
513
|
+
|
|
514
|
+
/** 水合策略类型 */
|
|
515
|
+
type HydrationStrategy = 'lazy' | 'eager' | 'idle';
|
|
516
|
+
/** 水合提示信息 */
|
|
517
|
+
interface HydrationHints {
|
|
518
|
+
/** 组件唯一标识 */
|
|
519
|
+
componentId: string;
|
|
520
|
+
/** 水合策略 */
|
|
521
|
+
strategy: HydrationStrategy;
|
|
522
|
+
/** 组件 props 快照 */
|
|
523
|
+
props: Record<string, unknown>;
|
|
524
|
+
}
|
|
525
|
+
/** 水合状态数据结构 */
|
|
526
|
+
interface HydrationState {
|
|
527
|
+
/** 组件水合提示列表 */
|
|
528
|
+
hints: HydrationHints[];
|
|
529
|
+
/** 全局初始状态 */
|
|
530
|
+
initialState?: Record<string, unknown>;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* 重置组件 ID 计数器(仅用于测试)
|
|
534
|
+
*/
|
|
535
|
+
declare function resetComponentIdCounter(): void;
|
|
536
|
+
/**
|
|
537
|
+
* 为 VNode 树添加水合标记
|
|
538
|
+
*
|
|
539
|
+
* @description
|
|
540
|
+
* 递归遍历 VNode 树,为每个元素节点添加 data-hydrate 属性,
|
|
541
|
+
* 用于客户端水合时识别对应的 SSR 输出节点。
|
|
542
|
+
* 同时根据 props 中的 hydrateStrategy 设置 data-hydrate-strategy 属性。
|
|
543
|
+
*
|
|
544
|
+
* @param vnode - 原始 VNode
|
|
545
|
+
* @returns 添加了水合标记的新 VNode(浅拷贝)
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```typescript
|
|
549
|
+
* const marked = createHydrationMarkers(vnode);
|
|
550
|
+
* // marked 的每个元素节点都带有 data-hydrate="lyt-hydrate-1" 等属性
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
declare function createHydrationMarkers(vnode: VNode): VNode;
|
|
554
|
+
/**
|
|
555
|
+
* 获取组件的水合策略
|
|
556
|
+
*
|
|
557
|
+
* @description
|
|
558
|
+
* 从 VNode 的 props 中读取 hydrateStrategy 字段,
|
|
559
|
+
* 返回对应的水合策略。如果未设置,默认返回 'eager'。
|
|
560
|
+
*
|
|
561
|
+
* @param vnode - 目标 VNode
|
|
562
|
+
* @returns 水合策略(lazy / eager / idle)
|
|
563
|
+
*
|
|
564
|
+
* @example
|
|
565
|
+
* ```typescript
|
|
566
|
+
* const strategy = getHydrationStrategy(vnode);
|
|
567
|
+
* // 'eager' | 'lazy' | 'idle'
|
|
568
|
+
* ```
|
|
569
|
+
*/
|
|
570
|
+
declare function getHydrationStrategy(vnode: VNode): HydrationStrategy;
|
|
571
|
+
/**
|
|
572
|
+
* 序列化客户端水合所需的初始状态
|
|
573
|
+
*
|
|
574
|
+
* @description
|
|
575
|
+
* 将任意状态对象序列化为可安全嵌入 HTML 的 JSON 字符串。
|
|
576
|
+
* 处理特殊值(undefined、函数、Symbol 等)以确保 JSON 安全。
|
|
577
|
+
*
|
|
578
|
+
* @param state - 要序列化的状态对象
|
|
579
|
+
* @returns JSON 字符串
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* ```typescript
|
|
583
|
+
* const serialized = serializeHydrationState({
|
|
584
|
+
* user: { name: 'Alice', age: 30 },
|
|
585
|
+
* items: [1, 2, 3],
|
|
586
|
+
* });
|
|
587
|
+
* // '{"user":{"name":"Alice","age":30},"items":[1,2,3]}'
|
|
588
|
+
* ```
|
|
589
|
+
*/
|
|
590
|
+
declare function serializeHydrationState(state: unknown): string;
|
|
591
|
+
/**
|
|
592
|
+
* 创建脱水状态(SSR 时序列化到 HTML 中的状态)
|
|
593
|
+
*
|
|
594
|
+
* @description
|
|
595
|
+
* 从 VNode 树中提取水合所需的信息,生成一段可嵌入 HTML 的 script 标签内容。
|
|
596
|
+
* 客户端加载时读取此状态进行水合。
|
|
597
|
+
*
|
|
598
|
+
* @param vnode - VNode 节点
|
|
599
|
+
* @param initialState - 可选的全局初始状态
|
|
600
|
+
* @returns 可嵌入 HTML 的 script 标签字符串
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* ```typescript
|
|
604
|
+
* const script = createDehydratedState(vnode, {
|
|
605
|
+
* user: { name: 'Alice' },
|
|
606
|
+
* });
|
|
607
|
+
* // <script id="__LYT_DEHYDRATED_STATE__" type="application/json">...</script>
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
declare function createDehydratedState(vnode: VNode, initialState?: Record<string, unknown>): string;
|
|
611
|
+
|
|
612
|
+
export { type ComponentDehydratedState, type DataPrefetchContext, type EnhancedStreamRenderOptions, type HydrationHints, type HydrationState, type HydrationStrategy, type PrefetchResult, type PrefetchableComponent, type SSGOptions, type SSGPage, ServerComponent, type ServerComponentContext, type ServerComponentRegistration, type ServerLifecycleHook, type StreamRenderOptions, VirtualList, buildDehydratedState, clearISRCache, collectPrefetchComponents, createDehydratedState, createHydrationMarkers, createISRMiddleware, _default as default, generateRouteManifest, generateStaticPages, getHydrationStrategy, getISRCacheStats, prefetchAllComponents, registerServerComponent, renderToHtml, renderToStream, renderToStreamAsync, renderToStreamEnhanced, renderToString, resetComponentIdCounter, revalidateOnDemand, safeDeserializeState, safeSerializeState, serializeHydrationState, stateManager, unregisterServerComponent, validatePages, writeStaticFiles };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
import { VNode } from '@lytjs/vdom';
|
|
2
|
+
import * as _lytjs_component from '@lytjs/component';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @lytjs/ssr - 服务端渲染
|
|
6
|
+
*
|
|
7
|
+
* 将 VNode 渲染为 HTML 字符串
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 渲染 VNode 为 HTML 字符串
|
|
12
|
+
*/
|
|
13
|
+
declare function renderToString(vnode: VNode | VNode[] | string | number | null | undefined): string;
|
|
14
|
+
/**
|
|
15
|
+
* 渲染完整的 HTML 页面
|
|
16
|
+
*/
|
|
17
|
+
declare function renderToHtml(vnode: VNode | VNode[], options?: {
|
|
18
|
+
title?: string;
|
|
19
|
+
lang?: string;
|
|
20
|
+
head?: string;
|
|
21
|
+
bodyAttrs?: Record<string, string>;
|
|
22
|
+
}): string;
|
|
23
|
+
declare const _default: {
|
|
24
|
+
renderToString: typeof renderToString;
|
|
25
|
+
renderToHtml: typeof renderToHtml;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @lytjs/ssr - 虚拟列表组件
|
|
30
|
+
*
|
|
31
|
+
* 高性能大数据列表渲染
|
|
32
|
+
*/
|
|
33
|
+
declare const VirtualList: _lytjs_component.ComponentOptions<Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @lytjs/ssr - 流式服务端渲染
|
|
37
|
+
*
|
|
38
|
+
* 将 VNode 渲染为 ReadableStream,支持分块发送和 Suspense 边界
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** 流式渲染配置选项 */
|
|
42
|
+
interface StreamRenderOptions {
|
|
43
|
+
/** 每个分块的最大字节数,默认 4096 */
|
|
44
|
+
chunkSize?: number;
|
|
45
|
+
/** Shell 就绪回调(Suspense 边界之前的初始内容已发送) */
|
|
46
|
+
onShellReady?: () => void;
|
|
47
|
+
/** 错误回调 */
|
|
48
|
+
onError?: (error: Error) => void;
|
|
49
|
+
/** 流式渲染超时时间(毫秒),默认 30000 */
|
|
50
|
+
timeout?: number;
|
|
51
|
+
/** 当渲染超时时的回退 HTML 内容 */
|
|
52
|
+
fallbackHtml?: string;
|
|
53
|
+
/** 流控制:每秒最大字节数,用于防止突发流量 */
|
|
54
|
+
maxBytesPerSecond?: number;
|
|
55
|
+
/** 是否启用错误恢复模式,默认 true */
|
|
56
|
+
errorRecovery?: boolean;
|
|
57
|
+
/** 单个组件渲染超时(毫秒),默认 5000 */
|
|
58
|
+
componentTimeout?: number;
|
|
59
|
+
}
|
|
60
|
+
/** 异步数据预取上下文 */
|
|
61
|
+
interface DataPrefetchContext {
|
|
62
|
+
/** 路由路径 */
|
|
63
|
+
path?: string;
|
|
64
|
+
/** 路由参数 */
|
|
65
|
+
params?: Record<string, string>;
|
|
66
|
+
/** 查询参数 */
|
|
67
|
+
query?: Record<string, string>;
|
|
68
|
+
}
|
|
69
|
+
/** 异步数据预取结果 */
|
|
70
|
+
interface PrefetchResult {
|
|
71
|
+
/** 预取的数据 */
|
|
72
|
+
data: Record<string, unknown>;
|
|
73
|
+
/** 数据过期时间(毫秒) */
|
|
74
|
+
ttl?: number;
|
|
75
|
+
}
|
|
76
|
+
/** 支持数据预取的组件接口 */
|
|
77
|
+
interface PrefetchableComponent {
|
|
78
|
+
/** 预取数据方法 */
|
|
79
|
+
prefetch?: (context: DataPrefetchContext) => Promise<PrefetchResult>;
|
|
80
|
+
}
|
|
81
|
+
/** 流式渲染增强选项 */
|
|
82
|
+
interface EnhancedStreamRenderOptions extends StreamRenderOptions {
|
|
83
|
+
/** 数据预取上下文 */
|
|
84
|
+
prefetchContext?: DataPrefetchContext;
|
|
85
|
+
/** 数据预取完成回调 */
|
|
86
|
+
onDataPrefetched?: (data: Record<string, unknown>) => void;
|
|
87
|
+
/** 是否启用渐进式水合 */
|
|
88
|
+
progressiveHydration?: boolean;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 将 VNode 渲染为 ReadableStream(流式服务端渲染)
|
|
92
|
+
*
|
|
93
|
+
* @description
|
|
94
|
+
* 将 VNode 树渲染为 HTML 并通过 ReadableStream 分块发送。
|
|
95
|
+
* 支持以下特性:
|
|
96
|
+
* - 按组件边界拆分 HTML 分块
|
|
97
|
+
* - 支持 Suspense 边界(先发送 shell,再发送异步内容)
|
|
98
|
+
* - 使用 TextEncoder 编码为 Uint8Array
|
|
99
|
+
* - 可配置分块大小和回调
|
|
100
|
+
* - 超时控制和错误恢复
|
|
101
|
+
* - 流速率控制
|
|
102
|
+
*
|
|
103
|
+
* @param vnode - 要渲染的 VNode
|
|
104
|
+
* @param options - 流式渲染配置选项
|
|
105
|
+
* @returns ReadableStream<Uint8Array>
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const stream = renderToStream(vnode, {
|
|
110
|
+
* chunkSize: 2048,
|
|
111
|
+
* onShellReady: () => console.log('Shell 已发送'),
|
|
112
|
+
* onError: (err) => console.error(err),
|
|
113
|
+
* timeout: 30000,
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* for await (const chunk of stream) {
|
|
117
|
+
* response.write(chunk);
|
|
118
|
+
* }
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
declare function renderToStream(vnode: VNode, options?: StreamRenderOptions): ReadableStream<Uint8Array>;
|
|
122
|
+
/**
|
|
123
|
+
* 将 VNode 渲染为异步 ReadableStream(支持异步组件和数据预取)
|
|
124
|
+
*
|
|
125
|
+
* @description
|
|
126
|
+
* 与 renderToStream 类似,但支持异步组件和数据预取。
|
|
127
|
+
* 遇到返回 Promise 的组件时先发送占位内容,等 Promise 解析后再发送实际内容。
|
|
128
|
+
*
|
|
129
|
+
* @param vnode - 要渲染的 VNode
|
|
130
|
+
* @param options - 流式渲染配置选项
|
|
131
|
+
* @returns ReadableStream<Uint8Array>
|
|
132
|
+
*/
|
|
133
|
+
declare function renderToStreamAsync(vnode: VNode, options?: EnhancedStreamRenderOptions): ReadableStream<Uint8Array>;
|
|
134
|
+
/**
|
|
135
|
+
* 增强型流式渲染(包含数据预取和渐进式水合)
|
|
136
|
+
*
|
|
137
|
+
* @description
|
|
138
|
+
* 完整的流式渲染解决方案,包含数据预取、渐进式水合等高级特性。
|
|
139
|
+
*
|
|
140
|
+
* @param vnode - 要渲染的 VNode
|
|
141
|
+
* @param options - 增强型流式渲染配置
|
|
142
|
+
* @returns Promise<{ stream: ReadableStream<Uint8Array>; dehydratedState: Record<string, any> }>
|
|
143
|
+
*/
|
|
144
|
+
declare function renderToStreamEnhanced(vnode: VNode, options?: EnhancedStreamRenderOptions): Promise<{
|
|
145
|
+
stream: ReadableStream<Uint8Array>;
|
|
146
|
+
dehydratedState: Record<string, unknown>;
|
|
147
|
+
}>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @lytjs/ssr - 静态站点生成(SSG)
|
|
151
|
+
*
|
|
152
|
+
* 预渲染页面配置为静态 HTML 文件
|
|
153
|
+
*/
|
|
154
|
+
|
|
155
|
+
/** SSG 页面配置 */
|
|
156
|
+
interface SSGPage {
|
|
157
|
+
/** 页面路径,如 '/' 或 '/about' */
|
|
158
|
+
path: string;
|
|
159
|
+
/** 页面组件 VNode */
|
|
160
|
+
component: VNode;
|
|
161
|
+
/** 可选布局组件 */
|
|
162
|
+
layout?: VNode;
|
|
163
|
+
/** 页面头部信息 */
|
|
164
|
+
head?: {
|
|
165
|
+
/** 页面标题 */
|
|
166
|
+
title?: string;
|
|
167
|
+
/** 元信息键值对 */
|
|
168
|
+
meta?: Record<string, string>;
|
|
169
|
+
};
|
|
170
|
+
/** 额外的脚本标签 */
|
|
171
|
+
scripts?: string[];
|
|
172
|
+
/** 额外的样式标签 */
|
|
173
|
+
styles?: string[];
|
|
174
|
+
}
|
|
175
|
+
/** SSG 生成选项 */
|
|
176
|
+
interface SSGOptions {
|
|
177
|
+
/** 站点基础 URL,默认 '/' */
|
|
178
|
+
baseUrl?: string;
|
|
179
|
+
/** 输出目录,默认 'dist' */
|
|
180
|
+
outDir?: string;
|
|
181
|
+
/** 默认页面标题 */
|
|
182
|
+
defaultTitle?: string;
|
|
183
|
+
/** 默认语言 */
|
|
184
|
+
lang?: string;
|
|
185
|
+
/** 是否生成 sitemap */
|
|
186
|
+
generateSitemap?: boolean;
|
|
187
|
+
/** 站点名称(用于 sitemap) */
|
|
188
|
+
siteName?: string;
|
|
189
|
+
/** 是否使用哈希路由 */
|
|
190
|
+
hashMode?: boolean;
|
|
191
|
+
/** 全局额外脚本 */
|
|
192
|
+
globalScripts?: string[];
|
|
193
|
+
/** 全局额外样式 */
|
|
194
|
+
globalStyles?: string[];
|
|
195
|
+
/** ISR 配置(增量静态再生成) */
|
|
196
|
+
isr?: {
|
|
197
|
+
/** 重新验证间隔(秒),0 表示按需重新验证 */
|
|
198
|
+
revalidate?: number;
|
|
199
|
+
/** 是否启用增量静态再生成 */
|
|
200
|
+
enabled?: boolean;
|
|
201
|
+
/** 预渲染 fallback 页面 */
|
|
202
|
+
fallback?: 'blocking' | boolean;
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 将生成的 HTML 写入文件系统
|
|
207
|
+
*
|
|
208
|
+
* @description
|
|
209
|
+
* 将 generateStaticPages 生成的结果写入到指定的输出目录。
|
|
210
|
+
* 会自动创建所需的目录结构。
|
|
211
|
+
*
|
|
212
|
+
* @param pages - 页面配置数组
|
|
213
|
+
* @param options - SSG 选项
|
|
214
|
+
* @returns Promise<void>
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* await writeStaticFiles(pages, { outDir: 'build' });
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
declare function writeStaticFiles(pages: SSGPage[], options?: SSGOptions): Promise<void>;
|
|
222
|
+
/**
|
|
223
|
+
* 预渲染页面配置数组为静态 HTML
|
|
224
|
+
*
|
|
225
|
+
* @description
|
|
226
|
+
* 接受页面配置数组,为每个页面生成完整的 HTML 内容。
|
|
227
|
+
* 返回一个 Map,键为文件路径,值为 HTML 内容。
|
|
228
|
+
*
|
|
229
|
+
* @param pages - 页面配置数组
|
|
230
|
+
* @param options - SSG 生成选项
|
|
231
|
+
* @returns Map<string, string> 文件路径 -> HTML 内容
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* const pages: SSGPage[] = [
|
|
236
|
+
* {
|
|
237
|
+
* path: '/',
|
|
238
|
+
* component: h('div', {}, 'Home'),
|
|
239
|
+
* head: { title: '首页', meta: { description: '欢迎' } },
|
|
240
|
+
* },
|
|
241
|
+
* {
|
|
242
|
+
* path: '/about',
|
|
243
|
+
* component: h('div', {}, 'About'),
|
|
244
|
+
* },
|
|
245
|
+
* ];
|
|
246
|
+
*
|
|
247
|
+
* const results = generateStaticPages(pages, {
|
|
248
|
+
* baseUrl: 'https://example.com',
|
|
249
|
+
* defaultTitle: 'My Site',
|
|
250
|
+
* });
|
|
251
|
+
*
|
|
252
|
+
* for (const [filePath, html] of results) {
|
|
253
|
+
* console.log(filePath, html);
|
|
254
|
+
* }
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
declare function generateStaticPages(pages: SSGPage[], options?: SSGOptions): Map<string, string>;
|
|
258
|
+
/**
|
|
259
|
+
* 生成页面路由清单
|
|
260
|
+
*
|
|
261
|
+
* @description
|
|
262
|
+
* 根据页面配置生成一个 JSON 格式的路由清单,
|
|
263
|
+
* 可用于客户端路由注册或构建分析。
|
|
264
|
+
*
|
|
265
|
+
* @param pages - 页面配置数组
|
|
266
|
+
* @param baseUrl - 站点基础 URL
|
|
267
|
+
* @returns 路由信息数组
|
|
268
|
+
*/
|
|
269
|
+
declare function generateRouteManifest(pages: SSGPage[], baseUrl?: string): Array<{
|
|
270
|
+
path: string;
|
|
271
|
+
filePath: string;
|
|
272
|
+
title?: string;
|
|
273
|
+
}>;
|
|
274
|
+
/**
|
|
275
|
+
* 验证页面配置数组的合法性
|
|
276
|
+
*
|
|
277
|
+
* @description
|
|
278
|
+
* 检查每个页面配置是否包含必要的字段(path 和 component),
|
|
279
|
+
* 以及路径是否合法。返回错误信息数组。
|
|
280
|
+
*
|
|
281
|
+
* @param pages - 页面配置数组
|
|
282
|
+
* @returns 错误信息数组,空数组表示全部合法
|
|
283
|
+
*/
|
|
284
|
+
declare function validatePages(pages: SSGPage[]): string[];
|
|
285
|
+
/**
|
|
286
|
+
* 创建 ISR 中间件
|
|
287
|
+
*
|
|
288
|
+
* @description
|
|
289
|
+
* 创建用于 Express/Fastify 等框架的 ISR 中间件,
|
|
290
|
+
* 支持增量静态再生成和背景重新验证。
|
|
291
|
+
*
|
|
292
|
+
* @param options - ISR 选项
|
|
293
|
+
* @returns 中间件函数
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* import express from 'express';
|
|
298
|
+
* import { createISRMiddleware, generateStaticPages } from '@lytjs/ssr';
|
|
299
|
+
*
|
|
300
|
+
* const app = express();
|
|
301
|
+
*
|
|
302
|
+
* // 预生成的页面
|
|
303
|
+
* const pages = [
|
|
304
|
+
* { path: '/', component: homeComponent },
|
|
305
|
+
* ];
|
|
306
|
+
*
|
|
307
|
+
* const staticPages = generateStaticPages(pages);
|
|
308
|
+
*
|
|
309
|
+
* app.use(createISRMiddleware({
|
|
310
|
+
* staticPages,
|
|
311
|
+
* revalidate: 60, // 60秒后重新验证
|
|
312
|
+
* async regenerate(path) {
|
|
313
|
+
* const page = pages.find(p => p.path === path);
|
|
314
|
+
* if (page) {
|
|
315
|
+
* return generateStaticPages([page]).get('/index.html')!;
|
|
316
|
+
* }
|
|
317
|
+
* throw new Error('Page not found');
|
|
318
|
+
* }
|
|
319
|
+
* }));
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
declare function createISRMiddleware(options: {
|
|
323
|
+
/** 预生成的静态页面 */
|
|
324
|
+
staticPages: Map<string, string>;
|
|
325
|
+
/** 重新验证间隔(秒) */
|
|
326
|
+
revalidate?: number;
|
|
327
|
+
/** 是否启用 ISR */
|
|
328
|
+
enabled?: boolean;
|
|
329
|
+
/** 重新生成页面的函数 */
|
|
330
|
+
regenerate?: (path: string) => Promise<string>;
|
|
331
|
+
}): (req: any, res: any, next: any) => Promise<any>;
|
|
332
|
+
/**
|
|
333
|
+
* 触发按需重新验证
|
|
334
|
+
*
|
|
335
|
+
* @description
|
|
336
|
+
* 手动触发特定路径的重新验证,适合于内容更新后调用。
|
|
337
|
+
*
|
|
338
|
+
* @param path - 要重新验证的路径
|
|
339
|
+
* @param regenerate - 重新生成页面的函数
|
|
340
|
+
* @returns Promise<string> 新生成的 HTML
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* ```typescript
|
|
344
|
+
* // 当博客文章更新时
|
|
345
|
+
* await revalidateOnDemand(
|
|
346
|
+
* '/blog/my-post',
|
|
347
|
+
* async () => generatePostHTML('my-post')
|
|
348
|
+
* );
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
declare function revalidateOnDemand(path: string, regenerate: () => Promise<string>): Promise<string>;
|
|
352
|
+
/**
|
|
353
|
+
* 获取 ISR 缓存统计信息
|
|
354
|
+
*
|
|
355
|
+
* @description
|
|
356
|
+
* 获取当前 ISR 缓存的统计信息,用于监控和调试。
|
|
357
|
+
*
|
|
358
|
+
* @returns 缓存统计信息
|
|
359
|
+
*/
|
|
360
|
+
declare function getISRCacheStats(): {
|
|
361
|
+
total: number;
|
|
362
|
+
paths: string[];
|
|
363
|
+
};
|
|
364
|
+
/**
|
|
365
|
+
* 清除 ISR 缓存
|
|
366
|
+
*
|
|
367
|
+
* @description
|
|
368
|
+
* 清除指定路径或所有过期的缓存。
|
|
369
|
+
*
|
|
370
|
+
* @param path - 可选,要清除的特定路径
|
|
371
|
+
* @param maxAge - 可选,清除超过指定秒数的缓存
|
|
372
|
+
*/
|
|
373
|
+
declare function clearISRCache(path?: string, maxAge?: number): void;
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* @lytjs/ssr - 服务端组件完善
|
|
377
|
+
*
|
|
378
|
+
* 提供服务端组件生命周期管理、数据预取优化、状态序列化等功能
|
|
379
|
+
*/
|
|
380
|
+
|
|
381
|
+
/** 服务端组件生命周期钩子类型 */
|
|
382
|
+
type ServerLifecycleHook = (context: ServerComponentContext) => Promise<void> | void;
|
|
383
|
+
/** 服务端组件上下文 */
|
|
384
|
+
interface ServerComponentContext {
|
|
385
|
+
/** 组件唯一 ID */
|
|
386
|
+
componentId: string;
|
|
387
|
+
/** 路由信息 */
|
|
388
|
+
route?: {
|
|
389
|
+
path: string;
|
|
390
|
+
params: Record<string, string>;
|
|
391
|
+
query: Record<string, string>;
|
|
392
|
+
};
|
|
393
|
+
/** 请求上下文 */
|
|
394
|
+
request?: {
|
|
395
|
+
headers: Record<string, string | undefined>;
|
|
396
|
+
cookies: Record<string, string>;
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/** 服务端组件注册信息 */
|
|
400
|
+
interface ServerComponentRegistration {
|
|
401
|
+
/** 组件名称 */
|
|
402
|
+
name: string;
|
|
403
|
+
/** 组件渲染函数 */
|
|
404
|
+
render: () => VNode;
|
|
405
|
+
/** 服务端初始化钩子 */
|
|
406
|
+
onServerInit?: ServerLifecycleHook;
|
|
407
|
+
/** 数据预取钩子 */
|
|
408
|
+
prefetch?: (context: DataPrefetchContext) => Promise<PrefetchResult>;
|
|
409
|
+
/** 服务端清理钩子 */
|
|
410
|
+
onServerCleanup?: ServerLifecycleHook;
|
|
411
|
+
}
|
|
412
|
+
/** 服务端组件状态管理器 */
|
|
413
|
+
declare class ServerComponentStateManager {
|
|
414
|
+
/** 注册的组件 */
|
|
415
|
+
private registrations;
|
|
416
|
+
/** 正在执行的预取请求 */
|
|
417
|
+
private pendingPrefetches;
|
|
418
|
+
/** 组件初始化状态 */
|
|
419
|
+
private initializationStates;
|
|
420
|
+
/**
|
|
421
|
+
* 注册服务端组件
|
|
422
|
+
*/
|
|
423
|
+
register(name: string, registration: ServerComponentRegistration): void;
|
|
424
|
+
/**
|
|
425
|
+
* 取消注册服务端组件
|
|
426
|
+
*/
|
|
427
|
+
unregister(name: string): void;
|
|
428
|
+
/**
|
|
429
|
+
* 获取已注册的组件
|
|
430
|
+
*/
|
|
431
|
+
getRegistration(name: string): ServerComponentRegistration | undefined;
|
|
432
|
+
/**
|
|
433
|
+
* 初始化服务端组件
|
|
434
|
+
*/
|
|
435
|
+
initializeComponent(name: string, context: ServerComponentContext): Promise<void>;
|
|
436
|
+
/**
|
|
437
|
+
* 清理服务端组件
|
|
438
|
+
*/
|
|
439
|
+
cleanupComponent(name: string, context: ServerComponentContext): Promise<void>;
|
|
440
|
+
/**
|
|
441
|
+
* 预取组件数据(带缓存)
|
|
442
|
+
*/
|
|
443
|
+
prefetchComponentData(name: string, context: DataPrefetchContext, cacheKey?: string): Promise<PrefetchResult>;
|
|
444
|
+
/**
|
|
445
|
+
* 清除所有缓存
|
|
446
|
+
*/
|
|
447
|
+
clearAll(): void;
|
|
448
|
+
}
|
|
449
|
+
/** 全局状态管理器实例 */
|
|
450
|
+
declare const stateManager: ServerComponentStateManager;
|
|
451
|
+
/**
|
|
452
|
+
* 注册服务端组件
|
|
453
|
+
*/
|
|
454
|
+
declare function registerServerComponent(name: string, registration: ServerComponentRegistration): void;
|
|
455
|
+
/**
|
|
456
|
+
* 取消注册服务端组件
|
|
457
|
+
*/
|
|
458
|
+
declare function unregisterServerComponent(name: string): void;
|
|
459
|
+
/**
|
|
460
|
+
* 从 VNode 树中收集需要预取数据的组件
|
|
461
|
+
*/
|
|
462
|
+
declare function collectPrefetchComponents(vnode: VNode | VNode[] | string | number | null | undefined): string[];
|
|
463
|
+
/**
|
|
464
|
+
* 并发预取多个组件的数据
|
|
465
|
+
*/
|
|
466
|
+
declare function prefetchAllComponents(components: string[], context: DataPrefetchContext): Promise<Record<string, PrefetchResult>>;
|
|
467
|
+
/**
|
|
468
|
+
* 安全的状态序列化
|
|
469
|
+
* 处理循环引用、日期、正则表达式等特殊类型
|
|
470
|
+
*/
|
|
471
|
+
declare function safeSerializeState(state: unknown): string;
|
|
472
|
+
/**
|
|
473
|
+
* 安全的状态反序列化
|
|
474
|
+
* 恢复特殊类型
|
|
475
|
+
*/
|
|
476
|
+
declare function safeDeserializeState(serialized: string): unknown;
|
|
477
|
+
/**
|
|
478
|
+
* 创建组件脱水状态
|
|
479
|
+
*/
|
|
480
|
+
interface ComponentDehydratedState {
|
|
481
|
+
/** 组件名称 */
|
|
482
|
+
componentName: string;
|
|
483
|
+
/** 组件 Props */
|
|
484
|
+
props: Record<string, unknown>;
|
|
485
|
+
/** 预取的数据 */
|
|
486
|
+
data?: Record<string, unknown>;
|
|
487
|
+
/** 错误信息 */
|
|
488
|
+
error?: string;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* 构建完整的脱水状态
|
|
492
|
+
*/
|
|
493
|
+
declare function buildDehydratedState(prefetchResults: Record<string, PrefetchResult>): Record<string, ComponentDehydratedState>;
|
|
494
|
+
/**
|
|
495
|
+
* 服务端组件管理器装饰器
|
|
496
|
+
*/
|
|
497
|
+
declare function ServerComponent(options: {
|
|
498
|
+
name: string;
|
|
499
|
+
prefetch?: (context: DataPrefetchContext) => Promise<PrefetchResult>;
|
|
500
|
+
onInit?: ServerLifecycleHook;
|
|
501
|
+
onCleanup?: ServerLifecycleHook;
|
|
502
|
+
}): (target: {
|
|
503
|
+
name?: string;
|
|
504
|
+
render?: () => VNode;
|
|
505
|
+
}) => void;
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* @lytjs/ssr - 组件级水合提示
|
|
509
|
+
*
|
|
510
|
+
* 提供水合标记、策略检测和状态序列化等辅助函数,
|
|
511
|
+
* 用于 SSR 输出中嵌入客户端水合所需的信息
|
|
512
|
+
*/
|
|
513
|
+
|
|
514
|
+
/** 水合策略类型 */
|
|
515
|
+
type HydrationStrategy = 'lazy' | 'eager' | 'idle';
|
|
516
|
+
/** 水合提示信息 */
|
|
517
|
+
interface HydrationHints {
|
|
518
|
+
/** 组件唯一标识 */
|
|
519
|
+
componentId: string;
|
|
520
|
+
/** 水合策略 */
|
|
521
|
+
strategy: HydrationStrategy;
|
|
522
|
+
/** 组件 props 快照 */
|
|
523
|
+
props: Record<string, unknown>;
|
|
524
|
+
}
|
|
525
|
+
/** 水合状态数据结构 */
|
|
526
|
+
interface HydrationState {
|
|
527
|
+
/** 组件水合提示列表 */
|
|
528
|
+
hints: HydrationHints[];
|
|
529
|
+
/** 全局初始状态 */
|
|
530
|
+
initialState?: Record<string, unknown>;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* 重置组件 ID 计数器(仅用于测试)
|
|
534
|
+
*/
|
|
535
|
+
declare function resetComponentIdCounter(): void;
|
|
536
|
+
/**
|
|
537
|
+
* 为 VNode 树添加水合标记
|
|
538
|
+
*
|
|
539
|
+
* @description
|
|
540
|
+
* 递归遍历 VNode 树,为每个元素节点添加 data-hydrate 属性,
|
|
541
|
+
* 用于客户端水合时识别对应的 SSR 输出节点。
|
|
542
|
+
* 同时根据 props 中的 hydrateStrategy 设置 data-hydrate-strategy 属性。
|
|
543
|
+
*
|
|
544
|
+
* @param vnode - 原始 VNode
|
|
545
|
+
* @returns 添加了水合标记的新 VNode(浅拷贝)
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```typescript
|
|
549
|
+
* const marked = createHydrationMarkers(vnode);
|
|
550
|
+
* // marked 的每个元素节点都带有 data-hydrate="lyt-hydrate-1" 等属性
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
declare function createHydrationMarkers(vnode: VNode): VNode;
|
|
554
|
+
/**
|
|
555
|
+
* 获取组件的水合策略
|
|
556
|
+
*
|
|
557
|
+
* @description
|
|
558
|
+
* 从 VNode 的 props 中读取 hydrateStrategy 字段,
|
|
559
|
+
* 返回对应的水合策略。如果未设置,默认返回 'eager'。
|
|
560
|
+
*
|
|
561
|
+
* @param vnode - 目标 VNode
|
|
562
|
+
* @returns 水合策略(lazy / eager / idle)
|
|
563
|
+
*
|
|
564
|
+
* @example
|
|
565
|
+
* ```typescript
|
|
566
|
+
* const strategy = getHydrationStrategy(vnode);
|
|
567
|
+
* // 'eager' | 'lazy' | 'idle'
|
|
568
|
+
* ```
|
|
569
|
+
*/
|
|
570
|
+
declare function getHydrationStrategy(vnode: VNode): HydrationStrategy;
|
|
571
|
+
/**
|
|
572
|
+
* 序列化客户端水合所需的初始状态
|
|
573
|
+
*
|
|
574
|
+
* @description
|
|
575
|
+
* 将任意状态对象序列化为可安全嵌入 HTML 的 JSON 字符串。
|
|
576
|
+
* 处理特殊值(undefined、函数、Symbol 等)以确保 JSON 安全。
|
|
577
|
+
*
|
|
578
|
+
* @param state - 要序列化的状态对象
|
|
579
|
+
* @returns JSON 字符串
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* ```typescript
|
|
583
|
+
* const serialized = serializeHydrationState({
|
|
584
|
+
* user: { name: 'Alice', age: 30 },
|
|
585
|
+
* items: [1, 2, 3],
|
|
586
|
+
* });
|
|
587
|
+
* // '{"user":{"name":"Alice","age":30},"items":[1,2,3]}'
|
|
588
|
+
* ```
|
|
589
|
+
*/
|
|
590
|
+
declare function serializeHydrationState(state: unknown): string;
|
|
591
|
+
/**
|
|
592
|
+
* 创建脱水状态(SSR 时序列化到 HTML 中的状态)
|
|
593
|
+
*
|
|
594
|
+
* @description
|
|
595
|
+
* 从 VNode 树中提取水合所需的信息,生成一段可嵌入 HTML 的 script 标签内容。
|
|
596
|
+
* 客户端加载时读取此状态进行水合。
|
|
597
|
+
*
|
|
598
|
+
* @param vnode - VNode 节点
|
|
599
|
+
* @param initialState - 可选的全局初始状态
|
|
600
|
+
* @returns 可嵌入 HTML 的 script 标签字符串
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* ```typescript
|
|
604
|
+
* const script = createDehydratedState(vnode, {
|
|
605
|
+
* user: { name: 'Alice' },
|
|
606
|
+
* });
|
|
607
|
+
* // <script id="__LYT_DEHYDRATED_STATE__" type="application/json">...</script>
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
declare function createDehydratedState(vnode: VNode, initialState?: Record<string, unknown>): string;
|
|
611
|
+
|
|
612
|
+
export { type ComponentDehydratedState, type DataPrefetchContext, type EnhancedStreamRenderOptions, type HydrationHints, type HydrationState, type HydrationStrategy, type PrefetchResult, type PrefetchableComponent, type SSGOptions, type SSGPage, ServerComponent, type ServerComponentContext, type ServerComponentRegistration, type ServerLifecycleHook, type StreamRenderOptions, VirtualList, buildDehydratedState, clearISRCache, collectPrefetchComponents, createDehydratedState, createHydrationMarkers, createISRMiddleware, _default as default, generateRouteManifest, generateStaticPages, getHydrationStrategy, getISRCacheStats, prefetchAllComponents, registerServerComponent, renderToHtml, renderToStream, renderToStreamAsync, renderToStreamEnhanced, renderToString, resetComponentIdCounter, revalidateOnDemand, safeDeserializeState, safeSerializeState, serializeHydrationState, stateManager, unregisterServerComponent, validatePages, writeStaticFiles };
|