weifuwu 0.55.2 → 0.56.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.
@@ -26,6 +26,7 @@
26
26
  * ```
27
27
  */
28
28
  import type { Middleware } from '../types.ts';
29
+ import type { Component, AsyncComponent } from '../client/vnode.ts';
29
30
  declare module '../types.ts' {
30
31
  interface Context {
31
32
  ui: {
@@ -35,6 +36,16 @@ declare module '../types.ts' {
35
36
  js: (entryPath: string) => Promise<Response>;
36
37
  /** 读取 CSS → CSS Response(支持包名 weifuwu/layout、weifuwu/components/style.css 或文件路径) */
37
38
  css: (entryPath: string) => Promise<Response>;
39
+ /**
40
+ * SSR 渲染组件 → HTML 片段(HtmlSafe,可直接内联进 ctx.ui.html 模板)
41
+ * 支持 async 工厂组件:await 工厂 → 数据进 HTML。
42
+ * opts.data(Map)收集 ctx.data 预取结果,用 ctx.ui.ssrData(data) 序列化进 __DATA__。
43
+ */
44
+ ssr: (Comp: Component | AsyncComponent, props?: Record<string, any>, opts?: {
45
+ data?: Map<string, unknown>;
46
+ }) => Promise<string>;
47
+ /** 序列化 SSR 数据存储 → <script>window.__DATA__=...</script>(HtmlSafe) */
48
+ ssrData: (data: Map<string, unknown>) => string;
38
49
  };
39
50
  }
40
51
  }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * uiSsr — 路由级 SSR 中间件:前端路由表驱动的自动服务端渲染
3
+ *
4
+ * 开发者只声明路由(path + component),GET 匹配即自动 SSR:
5
+ * 匹配 → 注入 params → ctx.ui.ssr 渲染组件(async 工厂 await)→ 页面模板 + __DATA__
6
+ * 未匹配 → next()(交给后续 API/静态/404)
7
+ *
8
+ * 与客户端 router() 共用同一份路由定义(route-match.ts),SPA/SSR 一个声明。
9
+ */
10
+ import type { Middleware } from '../types.ts';
11
+ import type { RouteDef } from '../client/types.ts';
12
+ export interface UiSsrOptions {
13
+ /** 前端路由定义(与 router() 共享同一份) */
14
+ routes: RouteDef[];
15
+ /** 客户端 bundle 路径(自动注入 <script src>,如 '/static/app.js') */
16
+ bundle?: string;
17
+ /** CSS 路径数组(自动注入 <link rel="stylesheet">,如 ['/static/style.css']) */
18
+ styles?: string[];
19
+ /** 自定义 title(默认取路由定义 title 或 'weifuwu') */
20
+ title?: (ctx: {
21
+ params: Record<string, string>;
22
+ def: RouteDef;
23
+ }) => string;
24
+ /** 自定义页面模板:返回完整 HTML(默认内置,含 head/root/__DATA__/styles/bundle) */
25
+ template?: (parts: {
26
+ html: string;
27
+ dataScript: string;
28
+ title: string;
29
+ bundle?: string;
30
+ styles?: string[];
31
+ }) => string;
32
+ }
33
+ /**
34
+ * 路由级 SSR 中间件:
35
+ *
36
+ * ```ts
37
+ * const app = new Router()
38
+ * app.use(uiSsr({ routes, bundle: '/static/app.js' }))
39
+ * ```
40
+ */
41
+ export declare function uiSsr(opts: UiSsrOptions): Middleware;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * 服务端 SSR 字符串遍历器 — async 工厂组件(形态 C)的 HTML 序列化
3
+ *
4
+ * 支持:
5
+ * - 同步组件(mount → render → VNode → HTML)
6
+ * - async 工厂组件(await 工厂 → 数据进 HTML;服务端不缓存定义,数据 per-request)
7
+ * - Fragment / Portal(内联子节点)
8
+ * - innerHTML prop(原样输出)、class/style 对象序列化
9
+ * - 事件处理器 / ref 剥离、文本自动转义(XSS)
10
+ * - 服务端 ctx shim($ no-op dirty、ctx.data 预取、selfId 隔离)
11
+ *
12
+ * 产物为 HtmlSafe 标记的安全 HTML 片段,可直接内联进 ctx.ui.html 模板。
13
+ */
14
+ import type { Component, AsyncComponent } from '../client/vnode.ts';
15
+ import { HtmlSafe } from './html-safe.ts';
16
+ export { HtmlSafe } from './html-safe.ts';
17
+ export interface SsrOptions {
18
+ /** 服务端数据存储:ctx.data 预取结果写入此处,调用方序列化进 __DATA__ */
19
+ data?: Map<string, unknown>;
20
+ }
21
+ /**
22
+ * SSR 渲染组件 → HTML 片段(HtmlSafe 标记,可直接内联进 ctx.ui.html 模板,不二次转义)。
23
+ *
24
+ * ```ts
25
+ * const data = new Map()
26
+ * const html = await ctx.ui.ssr(BlogPage, { slug }, { data })
27
+ * return ctx.ui.html`
28
+ * <div id="root">${html}</div>
29
+ * ${ctx.ui.ssrData(data)}
30
+ * `
31
+ * ```
32
+ */
33
+ export declare function ssrToString(Comp: Component | AsyncComponent, props: Record<string, any>, serverCtx: any, opts?: SsrOptions): Promise<HtmlSafe>;
34
+ /** 序列化数据存储 → window.__DATA__ 脚本(防 XSS:转义 <) */
35
+ export declare function serializeData(data: Map<string, unknown>): string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "weifuwu",
3
3
  "type": "module",
4
- "version": "0.55.2",
4
+ "version": "0.56.0",
5
5
  "description": "AI SaaS framework — (req, ctx) => Response",
6
6
  "exports": {
7
7
  ".": {
@@ -22,7 +22,8 @@
22
22
  "types": "./dist/components/index.d.ts",
23
23
  "default": "./dist/components/index.js"
24
24
  },
25
- "./components/style.css": "./dist/components/style.css"
25
+ "./components/style.css": "./dist/components/style.css",
26
+ "./dev": "./dist/dev/index.js"
26
27
  },
27
28
  "files": [
28
29
  "dist/",
@@ -35,9 +36,12 @@
35
36
  "pretest": "docker compose up -d --wait postgres redis 2>/dev/null; sleep 1",
36
37
  "test": "node --env-file=.env --test 'src/test/**/*.test.ts' 'src/components/**/*.test.ts' 'src/db/**/*.test.ts'",
37
38
  "release": "node scripts/release.mjs",
38
- "release:dry": "node scripts/release.mjs --dry-run"
39
+ "release:dry": "node scripts/release.mjs --dry-run",
40
+ "demo": "node --import weifuwu/dev --env-file=.env apps/demo/server.ts",
41
+ "demo:build": "node apps/demo/scripts/build.mjs"
39
42
  },
40
43
  "dependencies": {
44
+ "esbuild": "^0.28.1",
41
45
  "graphql": "^16",
42
46
  "ws": "^8"
43
47
  },
@@ -62,7 +66,6 @@
62
66
  "@tailwindcss/postcss": "^4.3.3",
63
67
  "@types/node": "^25",
64
68
  "@types/ws": "^8",
65
- "esbuild": "^0.28.1",
66
69
  "ioredis": "^5.11.1",
67
70
  "jsdom": "^29.1.1",
68
71
  "postcss": "^8.5.19",