@finesoft/front 0.5.0 → 0.5.2

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.
Files changed (128) hide show
  1. package/README.md +4 -4
  2. package/dist/Outlet.svelte +39 -0
  3. package/dist/Outlet.svelte.d.ts +7 -0
  4. package/dist/browser-DIU6Sxl3.mjs +1237 -0
  5. package/dist/browser-kFMjlLGT.d.mts +262 -0
  6. package/dist/browser.d.mts +7 -2
  7. package/dist/browser.mjs +9 -1
  8. package/dist/controller-types-CgmJ6-le.d.mts +16 -0
  9. package/dist/cookies-Bpf9VayB.d.mts +779 -0
  10. package/dist/fetch-policy-BHT8RtrL.mjs +82 -0
  11. package/dist/host-guard-DDWxLpFL.mjs +222 -0
  12. package/dist/http-B6CJqDyf.d.mts +46 -0
  13. package/dist/http-CaxrMD1A.d.mts +1 -0
  14. package/dist/http-D70PL72H.mjs +257 -0
  15. package/dist/http.d.mts +3 -0
  16. package/dist/http.mjs +2 -0
  17. package/dist/index-node.d.mts +15 -0
  18. package/dist/index-node.mjs +15 -0
  19. package/dist/index.d.mts +48 -698
  20. package/dist/index.mjs +44 -261
  21. package/dist/load-node.d.mts +5 -0
  22. package/dist/load-node.mjs +10 -0
  23. package/dist/load-portable.d.mts +5 -0
  24. package/dist/load-portable.mjs +8 -0
  25. package/dist/lru-map-BKoUAySU.mjs +50 -0
  26. package/dist/messages-CAt2QdGr.mjs +140 -0
  27. package/dist/native-contract-DuR25hYB.d.mts +14 -0
  28. package/dist/native-contract.d.mts +2 -0
  29. package/dist/native-contract.mjs +1 -0
  30. package/dist/node-D9hB4dsz.d.mts +35 -0
  31. package/dist/node.d.mts +2 -0
  32. package/dist/node.mjs +59 -0
  33. package/dist/path-CGFl2w7D.mjs +113 -0
  34. package/dist/path-CXT6xGPO.d.mts +261 -0
  35. package/dist/portable-CaxrMD1A.d.mts +1 -0
  36. package/dist/portable.d.mts +11 -0
  37. package/dist/portable.mjs +12 -0
  38. package/dist/proxy-1SphZ7x7.mjs +436 -0
  39. package/dist/proxy-2dSWO-Xw.d.mts +53 -0
  40. package/dist/public-types-BcJM-AYc.mjs +835 -0
  41. package/dist/react-DhwBRw01.d.mts +16 -0
  42. package/dist/react.d.mts +3 -0
  43. package/dist/react.mjs +29 -0
  44. package/dist/rolldown-runtime-B4iAMlE-.mjs +35 -0
  45. package/dist/secure-fetch-Xlht2jd7.d.mts +30 -0
  46. package/dist/server-controller-proxy-BkVuVWVD.d.mts +38 -0
  47. package/dist/session-DnB4ZC3x.d.mts +1279 -0
  48. package/dist/src-Ftl_0rhu.mjs +28 -0
  49. package/dist/src-qwx7Vw8g.mjs +3807 -0
  50. package/dist/ssr-BEUNDvbj.d.mts +210 -0
  51. package/dist/ssr-C8xnYXoY.mjs +357 -0
  52. package/dist/ssr.d.mts +3 -0
  53. package/dist/ssr.mjs +3 -0
  54. package/dist/svelte-Dr5to3SE.d.mts +16 -0
  55. package/dist/svelte.d.mts +3 -0
  56. package/dist/svelte.mjs +13 -0
  57. package/dist/typegen-C-WeJCtf.d.mts +12 -0
  58. package/dist/typegen-cli.d.mts +1 -0
  59. package/dist/typegen-cli.mjs +11 -0
  60. package/dist/typegen.d.mts +3 -0
  61. package/dist/typegen.mjs +2 -0
  62. package/dist/types-BuaZHRG7.mjs +402 -0
  63. package/dist/undici-CPfL25Hr.mjs +22262 -0
  64. package/dist/vite-Cj4SPA8D.d.mts +277 -0
  65. package/dist/vite.d.mts +4 -0
  66. package/dist/vite.mjs +2354 -0
  67. package/dist/vue-DGmzuKho.d.mts +32 -0
  68. package/dist/vue.d.mts +3 -0
  69. package/dist/vue.mjs +56 -0
  70. package/dist/web.d.mts +6 -0
  71. package/dist/web.mjs +8 -0
  72. package/dist/worker.d.mts +2 -0
  73. package/dist/worker.mjs +2 -0
  74. package/docs/01-getting-started.md +67 -199
  75. package/docs/02-routing-and-controllers.md +163 -241
  76. package/docs/03-middleware.md +10 -212
  77. package/docs/04-rendering-and-hydration.md +6 -333
  78. package/docs/05-i18n.md +7 -237
  79. package/docs/06-http-client.md +20 -263
  80. package/docs/07-di-container.md +23 -257
  81. package/docs/08-observability.md +6 -286
  82. package/docs/09-server-and-deployment.md +59 -219
  83. package/docs/10-features-platform-pwa.md +7 -231
  84. package/docs/11-navigation.md +143 -288
  85. package/docs/12-session-restoration.md +6 -214
  86. package/docs/README.md +7 -7
  87. package/docs/advanced/custom-action-handler.md +29 -229
  88. package/docs/advanced/custom-adapter.md +7 -259
  89. package/docs/advanced/custom-event-recorder.md +7 -312
  90. package/docs/advanced/inline-proxy-codegen.md +6 -185
  91. package/docs/advanced/multi-tenant-scopes.md +10 -323
  92. package/docs/engineering/ci-release-flow.md +35 -222
  93. package/docs/engineering/project-structure.md +34 -277
  94. package/docs/engineering/testing.md +8 -310
  95. package/docs/pitfalls/container-scope-leak.md +2 -214
  96. package/docs/pitfalls/i18n-bundle-size.md +6 -176
  97. package/docs/pitfalls/proxy-binary-payloads.md +8 -12
  98. package/docs/pitfalls/ssr-hydration-mismatch.md +4 -160
  99. package/docs/pitfalls/ssr-vs-csr-globals.md +9 -170
  100. package/docs/zh/01-getting-started.md +67 -199
  101. package/docs/zh/02-routing-and-controllers.md +166 -244
  102. package/docs/zh/03-middleware.md +10 -212
  103. package/docs/zh/04-rendering-and-hydration.md +6 -333
  104. package/docs/zh/05-i18n.md +7 -237
  105. package/docs/zh/06-http-client.md +20 -263
  106. package/docs/zh/07-di-container.md +23 -257
  107. package/docs/zh/08-observability.md +6 -283
  108. package/docs/zh/09-server-and-deployment.md +59 -219
  109. package/docs/zh/10-features-platform-pwa.md +7 -231
  110. package/docs/zh/11-navigation.md +130 -290
  111. package/docs/zh/12-session-restoration.md +6 -214
  112. package/docs/zh/README.md +4 -4
  113. package/docs/zh/advanced/custom-action-handler.md +29 -229
  114. package/docs/zh/advanced/custom-adapter.md +7 -259
  115. package/docs/zh/advanced/custom-event-recorder.md +7 -312
  116. package/docs/zh/advanced/inline-proxy-codegen.md +6 -185
  117. package/docs/zh/advanced/multi-tenant-scopes.md +10 -323
  118. package/docs/zh/engineering/ci-release-flow.md +35 -222
  119. package/docs/zh/engineering/project-structure.md +34 -277
  120. package/docs/zh/engineering/testing.md +8 -310
  121. package/docs/zh/pitfalls/container-scope-leak.md +2 -214
  122. package/docs/zh/pitfalls/i18n-bundle-size.md +6 -176
  123. package/docs/zh/pitfalls/proxy-binary-payloads.md +8 -12
  124. package/docs/zh/pitfalls/ssr-hydration-mismatch.md +4 -160
  125. package/docs/zh/pitfalls/ssr-vs-csr-globals.md +9 -170
  126. package/package.json +118 -20
  127. package/dist/browser-BYZq9Jp7.mjs +0 -2
  128. package/dist/browser-JTs2jqVY.d.mts +0 -2811
@@ -1,230 +1,98 @@
1
- # 1. 快速开始
1
+ # 快速开始
2
2
 
3
- 五分钟跑通一个 `@finesoft/front` 应用。读完你会有一个 Vue/React/Svelte 页面在服务端渲染、在浏览器 hydrate、并准备好部署。
3
+ 所有框架 API 统一使用 `from "@finesoft/front"`。React、VueSvelte 都由应用创建一个原生根,布局和 Provider 包住 Outlet。六套模板共用此接入方式。
4
4
 
5
- ## 先决条件
6
-
7
- - Node.js `>= 22.12.0`
8
- - 一个包管理器:pnpm(推荐)、npm 或 yarn
9
- - 一个视图层:Vue 3、React 19 或 Svelte 5 —— 文档用 Vue 举例,但每个示例都能 1:1 翻译
10
-
11
- ## 脚手架创建新应用
12
-
13
- ```bash
14
- npx @finesoft/create-app my-app
15
- cd my-app
16
- pnpm install
17
- pnpm dev
18
- ```
19
-
20
- 脚手架生成一个可运行的应用,路由、SSR、proxy 已经接好。打开 <http://localhost:5173>。
21
-
22
- 如果你想理解里面是怎么搭起来的,本页后面从零搭一份同样的配置。
23
-
24
- ## 加进已有项目
5
+ 先安装依赖。Node 要求 `^22.18.0 || >=24.11.0`,项目工具统一使用 Vite+。full 展示商品、搜索和守卫,minimal 展示 tabs/stack、输入草稿和会话恢复。
25
6
 
26
7
  ```bash
27
- pnpm add @finesoft/front
28
- pnpm add -D vite hono
8
+ vp dlx @finesoft/create-app my-app
9
+ vp install
29
10
  ```
30
11
 
31
- Peer 依赖:`hono >= 4.0.0`。可选但推荐:`@hono/node-server`(Node 部署)、`vite >= 5.0.0`(dev server)。
32
-
33
- ## 最小项目布局
34
-
35
- ```
36
- my-app/
37
- ├── src/
38
- │ ├── bootstrap.ts # 路由 + Controller(SSR + CSR 共享)
39
- │ ├── main.ts # 浏览器入口
40
- │ ├── ssr.ts # SSR 入口
41
- │ ├── App.vue # 根组件
42
- │ └── lib/
43
- │ └── controllers/
44
- │ └── home.ts
45
- ├── index.html
46
- ├── vite.config.ts
47
- ├── package.json
48
- └── tsconfig.json
49
- ```
50
-
51
- ## Vite 配置
12
+ ## 页面与路由
52
13
 
53
14
  ```ts
54
- // vite.config.ts
55
- import { finesoftFrontViteConfig } from "@finesoft/front";
56
- import vue from "@vitejs/plugin-vue";
57
- import { defineConfig } from "vite";
58
-
59
- export default defineConfig({
60
- plugins: [
61
- vue(),
62
- finesoftFrontViteConfig({
63
- ssr: { entry: "src/ssr.ts" },
64
- i18n: { messagesDir: "src/locales" },
65
- adapter: "auto",
66
- }),
67
- ],
15
+ // src/app-definition.ts
16
+ import { definePage, defineWebApp, markPublic } from "@finesoft/front";
17
+ export const home = definePage({
18
+ id: "home",
19
+ routes: ["/"],
20
+ handler: () => markPublic({ id: "home", pageType: "home" as const, title: "Home" }, []),
21
+ });
22
+ export const app = defineWebApp({
23
+ id: "example",
24
+ pages: [home],
25
+ getErrorPage: (status, title) => ({ id: String(status), pageType: "error", title }),
68
26
  });
69
27
  ```
70
28
 
71
- `finesoftFrontViteConfig` 加的东西:
72
-
73
- - 基于 Hono 的 dev server,每个请求都跑你的 SSR 入口
74
- - 从 `messagesDir` 自动加载 locale JSON
75
- - 构建管线同时产出客户端 bundle 和服务端入口
76
- - `adapter: "auto" | "node" | "vercel" | "cloudflare" | "netlify" | "static"` 自动接入平台 adapter
77
-
78
- ## Bootstrap(SSR CSR 共享)
79
-
80
- ```ts
81
- // src/bootstrap.ts
82
- import { type Framework, defineRoutes } from "@finesoft/front";
83
- import { HomeController } from "./lib/controllers/home";
84
-
85
- export function bootstrap(framework: Framework): void {
86
- defineRoutes(framework, [{ path: "/", intentId: "home", controller: new HomeController() }]);
29
+ ## 原生应用根
30
+
31
+ ```tsx
32
+ // src/App.tsx
33
+ import { Outlet as selectOutlet, type WebAppView } from "@finesoft/front";
34
+ import Home from "./pages/Home";
35
+ import ErrorPage from "./pages/ErrorPage";
36
+ const Outlet = selectOutlet("react");
37
+ const views = { home: Home, error: ErrorPage };
38
+ export default function App({ app }: { app: WebAppView }) {
39
+ return (
40
+ <div className="layout">
41
+ <Outlet app={app} views={views} />
42
+ </div>
43
+ );
87
44
  }
88
45
  ```
89
46
 
90
- 同一个 `bootstrap()` 在两端都跑。这就是 SSR CSR 解析 URL 完全一致的保证。
91
-
92
- ## Controller
93
-
94
- ```ts
95
- // src/lib/controllers/home.ts
96
- import { BaseController, type Container } from "@finesoft/front";
97
-
98
- interface HomePage {
99
- kind: "home";
100
- title: string;
101
- items: string[];
102
- }
47
+ 页面组件接收 `{ page, app, entry }`,可以使用布局提供的原生 context。真实 `<a href>` 链接自动接入同一导航流程;组合操作使用 `app.perform(action)`。类式加载逻辑可选用 `BaseController.execute({ params, query, context })`。
103
48
 
104
- export class HomeController extends BaseController<Record<string, string>, HomePage> {
105
- readonly intentId = "home";
106
-
107
- async execute(_params: Record<string, string>, _container: Container): Promise<HomePage> {
108
- return {
109
- kind: "home",
110
- title: "Welcome",
111
- items: ["one", "two", "three"],
112
- };
113
- }
49
+ ## 浏览器入口
114
50
 
115
- fallback(_params: Record<string, string>, error: unknown): HomePage {
116
- return { kind: "home", title: "Failed", items: [] };
117
- }
118
- }
51
+ ```tsx
52
+ // src/main.tsx
53
+ import { createBrowserApp } from "@finesoft/front";
54
+ import { createRoot, hydrateRoot } from "react-dom/client";
55
+ import { app as definition } from "./app-definition";
56
+ import App from "./App";
57
+ const target = document.getElementById("app")!;
58
+ const app = await createBrowserApp({ definition, target });
59
+ const root = app.shouldHydrate ? hydrateRoot(target, <App app={app} />) : createRoot(target);
60
+ if (!app.shouldHydrate) root.render(<App app={app} />);
61
+ await app.ready;
62
+ // Cleanup owned by the application:
63
+ // try { await app.dispose(); } finally { root.unmount(); }
119
64
  ```
120
65
 
121
- `BaseController` `execute()` 包在 `try/catch` 里,出错时调 `fallback()`。永远要写 `fallback` —— 原因见 [可观测性 · 错误处理](./08-observability.md#通过-fallback-处理错误)
66
+ `createBrowserApp` 返回可挂载的会话;先挂载,再等待 `ready`。Outlet 在原生提交后确认版本,随后才恢复会话。不要在挂载前等待 ready
122
67
 
123
- ## SSR 入口
124
-
125
- ```ts
126
- // src/ssr.ts
127
- import { createSSRRender, serializeServerData } from "@finesoft/front";
128
- import { createSSRApp } from "vue";
129
- import { renderToString } from "vue/server-renderer";
130
- import App from "./App.vue";
131
- import { bootstrap } from "./bootstrap";
68
+ ## SSR
132
69
 
70
+ ```tsx
71
+ // src/ssr.tsx
72
+ import { renderToString } from "react-dom/server";
73
+ import { createSSRRender } from "@finesoft/front";
74
+ import { app as definition } from "./app-definition";
75
+ import App from "./App";
133
76
  export const render = createSSRRender({
134
- bootstrap,
135
- getErrorPage: () => ({ kind: "error", title: "Error" }),
136
- async renderApp(page) {
137
- const html = await renderToString(createSSRApp(App, { page }));
138
- return { html, head: `<title>${(page as { title: string }).title}</title>`, css: "" };
139
- },
77
+ definition,
78
+ render: (app) => renderToString(<App app={app} />),
140
79
  });
141
-
142
- export { serializeServerData };
80
+ export { serializeServerData } from "@finesoft/front";
143
81
  ```
144
82
 
145
- `createSSRRender` 返回一个函数,接 URL 输出渲染后的 HTML + 序列化的 prefetched intent 数据。Vite 插件和 adapter 会替你调用,不需要手动调。
146
-
147
- ## 浏览器入口
83
+ ## Vite
148
84
 
149
85
  ```ts
150
- // src/main.ts
151
- import { startBrowserApp } from "@finesoft/front/browser";
152
- import { createSSRApp } from "vue";
153
- import App from "./App.vue";
154
- import { bootstrap } from "./bootstrap";
155
-
156
- startBrowserApp({
157
- bootstrap,
158
- mount(target, { framework }) {
159
- const app = createSSRApp(App, { framework });
160
- app.mount(target);
161
- },
86
+ import { defineConfig } from "vite-plus";
87
+ import react from "@vitejs/plugin-react";
88
+ import { finesoftFrontViteConfig } from "@finesoft/front";
89
+ export default defineConfig({
90
+ plugins: [react(), finesoftFrontViteConfig({ adapter: "node", ssr: { entry: "src/ssr.tsx" } })],
162
91
  });
163
92
  ```
164
93
 
165
- `startBrowserApp` DOM SSR 注入的 `PrefetchedIntents`,创建 `Framework`,跑同样的 `bootstrap()`,并触发首屏页面。`mount()` 跑的时候,框架已经准备好了初始的 `Page`。
166
-
167
- 客户端从 `@finesoft/front/browser` 导入(不是 `@finesoft/front`),避免把服务端模块带进客户端 bundle。
168
-
169
- ## 根组件(Vue 示例)
170
-
171
- ```vue
172
- <!-- src/App.vue -->
173
- <script setup lang="ts">
174
- import { computed } from "vue";
175
- import type { Framework } from "@finesoft/front";
176
-
177
- const props = defineProps<{ framework?: Framework; page?: { title: string; items: string[] } }>();
178
-
179
- // SSR 直接收到 page;CSR 从 framework 取当前页面。
180
- const page = computed(() => props.page ?? props.framework?.getCurrentPage());
181
- </script>
182
-
183
- <template>
184
- <main>
185
- <h1>{{ page?.title }}</h1>
186
- <ul>
187
- <li v-for="item in page?.items" :key="item">{{ item }}</li>
188
- </ul>
189
- </main>
190
- </template>
191
- ```
192
-
193
- ## index.html
194
-
195
- ```html
196
- <!doctype html>
197
- <html lang="en">
198
- <head>
199
- <meta charset="UTF-8" />
200
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
201
- <!--head-->
202
- </head>
203
- <body>
204
- <div id="app"><!--ssr--></div>
205
- <script type="module" src="/src/main.ts"></script>
206
- </body>
207
- </html>
208
- ```
209
-
210
- `<!--head-->` 和 `<!--ssr-->` 是框架注入 head 片段和渲染 HTML 的占位。占位名也通过 `SSR_PLACEHOLDERS` 导出。
211
-
212
- ## 跑起来
213
-
214
- ```bash
215
- pnpm dev # 带 HMR 的开发服务器
216
- pnpm build # 生产构建
217
- pnpm preview # 本地预览生产构建
218
- ```
219
-
220
- 完成。你现在有一个应用:
221
-
222
- - 服务端渲染,带 prefetch 数据
223
- - Hydrate 不再多发请求(SSR 数据通过 `PrefetchedIntents` 复用)
224
- - 客户端路由无刷新
225
- - 已准备好部署到任一支持的 adapter
94
+ Vue 使用 `Outlet("vue")`,使用 `createSSRApp` / `createApp` `renderToString`;Svelte 使用 `Outlet("svelte")`,使用 `hydrate` / `mount` `svelte/server` 的 `render`。参见对应模板。Svelte 在 `hydrate` 为 false 时先清空挂载目标,再执行 `mount`,避免旧的 SSR 错误页残留。
226
95
 
227
- ## 下一步
96
+ `useSnapshot("react", app)` 返回快照,`useSnapshot("vue", app)` 返回原生 ref,`useSnapshot("svelte", app)` 返回 store。选择参数必须是字符串字面量;Vite 插件把调用转换成所选原生实现的直接引用,保留组件身份、订阅与清理。
228
97
 
229
- - [路由与 Controller](./02-routing-and-controllers.md) —— 定义更多路由、控制渲染方式
230
- - [项目结构](./engineering/project-structure.md) —— 应用长大后的推荐布局
98
+ 插件在初始化时生成 `.finesoft/front.d.ts`,并维护 `tsconfig.json` 中仅针对 `@finesoft/front` 的类型路径。只安装使用的 UI 依赖,现有类型提示不变。将 `.finesoft/` 加入 `.gitignore`;依赖变化后重启开发进程。独立 `tsc` 或 Node 项目先运行 `vp exec finesoft-types`,也可从统一入口调用 `generateFrontTypes({ root })`。该映射仅用于类型,运行时仍解析正式包。