@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.
- package/README.md +4 -4
- package/dist/Outlet.svelte +39 -0
- package/dist/Outlet.svelte.d.ts +7 -0
- package/dist/browser-DIU6Sxl3.mjs +1237 -0
- package/dist/browser-kFMjlLGT.d.mts +262 -0
- package/dist/browser.d.mts +7 -2
- package/dist/browser.mjs +9 -1
- package/dist/controller-types-CgmJ6-le.d.mts +16 -0
- package/dist/cookies-Bpf9VayB.d.mts +779 -0
- package/dist/fetch-policy-BHT8RtrL.mjs +82 -0
- package/dist/host-guard-DDWxLpFL.mjs +222 -0
- package/dist/http-B6CJqDyf.d.mts +46 -0
- package/dist/http-CaxrMD1A.d.mts +1 -0
- package/dist/http-D70PL72H.mjs +257 -0
- package/dist/http.d.mts +3 -0
- package/dist/http.mjs +2 -0
- package/dist/index-node.d.mts +15 -0
- package/dist/index-node.mjs +15 -0
- package/dist/index.d.mts +48 -698
- package/dist/index.mjs +44 -261
- package/dist/load-node.d.mts +5 -0
- package/dist/load-node.mjs +10 -0
- package/dist/load-portable.d.mts +5 -0
- package/dist/load-portable.mjs +8 -0
- package/dist/lru-map-BKoUAySU.mjs +50 -0
- package/dist/messages-CAt2QdGr.mjs +140 -0
- package/dist/native-contract-DuR25hYB.d.mts +14 -0
- package/dist/native-contract.d.mts +2 -0
- package/dist/native-contract.mjs +1 -0
- package/dist/node-D9hB4dsz.d.mts +35 -0
- package/dist/node.d.mts +2 -0
- package/dist/node.mjs +59 -0
- package/dist/path-CGFl2w7D.mjs +113 -0
- package/dist/path-CXT6xGPO.d.mts +261 -0
- package/dist/portable-CaxrMD1A.d.mts +1 -0
- package/dist/portable.d.mts +11 -0
- package/dist/portable.mjs +12 -0
- package/dist/proxy-1SphZ7x7.mjs +436 -0
- package/dist/proxy-2dSWO-Xw.d.mts +53 -0
- package/dist/public-types-BcJM-AYc.mjs +835 -0
- package/dist/react-DhwBRw01.d.mts +16 -0
- package/dist/react.d.mts +3 -0
- package/dist/react.mjs +29 -0
- package/dist/rolldown-runtime-B4iAMlE-.mjs +35 -0
- package/dist/secure-fetch-Xlht2jd7.d.mts +30 -0
- package/dist/server-controller-proxy-BkVuVWVD.d.mts +38 -0
- package/dist/session-DnB4ZC3x.d.mts +1279 -0
- package/dist/src-Ftl_0rhu.mjs +28 -0
- package/dist/src-qwx7Vw8g.mjs +3807 -0
- package/dist/ssr-BEUNDvbj.d.mts +210 -0
- package/dist/ssr-C8xnYXoY.mjs +357 -0
- package/dist/ssr.d.mts +3 -0
- package/dist/ssr.mjs +3 -0
- package/dist/svelte-Dr5to3SE.d.mts +16 -0
- package/dist/svelte.d.mts +3 -0
- package/dist/svelte.mjs +13 -0
- package/dist/typegen-C-WeJCtf.d.mts +12 -0
- package/dist/typegen-cli.d.mts +1 -0
- package/dist/typegen-cli.mjs +11 -0
- package/dist/typegen.d.mts +3 -0
- package/dist/typegen.mjs +2 -0
- package/dist/types-BuaZHRG7.mjs +402 -0
- package/dist/undici-CPfL25Hr.mjs +22262 -0
- package/dist/vite-Cj4SPA8D.d.mts +277 -0
- package/dist/vite.d.mts +4 -0
- package/dist/vite.mjs +2354 -0
- package/dist/vue-DGmzuKho.d.mts +32 -0
- package/dist/vue.d.mts +3 -0
- package/dist/vue.mjs +56 -0
- package/dist/web.d.mts +6 -0
- package/dist/web.mjs +8 -0
- package/dist/worker.d.mts +2 -0
- package/dist/worker.mjs +2 -0
- package/docs/01-getting-started.md +67 -199
- package/docs/02-routing-and-controllers.md +163 -241
- package/docs/03-middleware.md +10 -212
- package/docs/04-rendering-and-hydration.md +6 -333
- package/docs/05-i18n.md +7 -237
- package/docs/06-http-client.md +20 -263
- package/docs/07-di-container.md +23 -257
- package/docs/08-observability.md +6 -286
- package/docs/09-server-and-deployment.md +59 -219
- package/docs/10-features-platform-pwa.md +7 -231
- package/docs/11-navigation.md +143 -288
- package/docs/12-session-restoration.md +6 -214
- package/docs/README.md +7 -7
- package/docs/advanced/custom-action-handler.md +29 -229
- package/docs/advanced/custom-adapter.md +7 -259
- package/docs/advanced/custom-event-recorder.md +7 -312
- package/docs/advanced/inline-proxy-codegen.md +6 -185
- package/docs/advanced/multi-tenant-scopes.md +10 -323
- package/docs/engineering/ci-release-flow.md +35 -222
- package/docs/engineering/project-structure.md +34 -277
- package/docs/engineering/testing.md +8 -310
- package/docs/pitfalls/container-scope-leak.md +2 -214
- package/docs/pitfalls/i18n-bundle-size.md +6 -176
- package/docs/pitfalls/proxy-binary-payloads.md +8 -12
- package/docs/pitfalls/ssr-hydration-mismatch.md +4 -160
- package/docs/pitfalls/ssr-vs-csr-globals.md +9 -170
- package/docs/zh/01-getting-started.md +67 -199
- package/docs/zh/02-routing-and-controllers.md +166 -244
- package/docs/zh/03-middleware.md +10 -212
- package/docs/zh/04-rendering-and-hydration.md +6 -333
- package/docs/zh/05-i18n.md +7 -237
- package/docs/zh/06-http-client.md +20 -263
- package/docs/zh/07-di-container.md +23 -257
- package/docs/zh/08-observability.md +6 -283
- package/docs/zh/09-server-and-deployment.md +59 -219
- package/docs/zh/10-features-platform-pwa.md +7 -231
- package/docs/zh/11-navigation.md +130 -290
- package/docs/zh/12-session-restoration.md +6 -214
- package/docs/zh/README.md +4 -4
- package/docs/zh/advanced/custom-action-handler.md +29 -229
- package/docs/zh/advanced/custom-adapter.md +7 -259
- package/docs/zh/advanced/custom-event-recorder.md +7 -312
- package/docs/zh/advanced/inline-proxy-codegen.md +6 -185
- package/docs/zh/advanced/multi-tenant-scopes.md +10 -323
- package/docs/zh/engineering/ci-release-flow.md +35 -222
- package/docs/zh/engineering/project-structure.md +34 -277
- package/docs/zh/engineering/testing.md +8 -310
- package/docs/zh/pitfalls/container-scope-leak.md +2 -214
- package/docs/zh/pitfalls/i18n-bundle-size.md +6 -176
- package/docs/zh/pitfalls/proxy-binary-payloads.md +8 -12
- package/docs/zh/pitfalls/ssr-hydration-mismatch.md +4 -160
- package/docs/zh/pitfalls/ssr-vs-csr-globals.md +9 -170
- package/package.json +118 -20
- package/dist/browser-BYZq9Jp7.mjs +0 -2
- package/dist/browser-JTs2jqVY.d.mts +0 -2811
|
@@ -1,230 +1,98 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 快速开始
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
所有框架 API 统一使用 `from "@finesoft/front"`。React、Vue、Svelte 都由应用创建一个原生根,布局和 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
|
-
|
|
28
|
-
|
|
8
|
+
vp dlx @finesoft/create-app my-app
|
|
9
|
+
vp install
|
|
29
10
|
```
|
|
30
11
|
|
|
31
|
-
|
|
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
|
-
//
|
|
55
|
-
import {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
116
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
135
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
## 浏览器入口
|
|
83
|
+
## Vite
|
|
148
84
|
|
|
149
85
|
```ts
|
|
150
|
-
|
|
151
|
-
import
|
|
152
|
-
import {
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
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 })`。该映射仅用于类型,运行时仍解析正式包。
|