weifuwu 0.71.0 → 0.73.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 +85 -60
- package/dist/components/Accordion/Accordion.d.ts +1 -1
- package/dist/components/Affix/Affix.d.ts +1 -1
- package/dist/components/AiChat/AiChat.d.ts +2 -2
- package/dist/components/Alert/Alert.d.ts +1 -1
- package/dist/components/AlertGroup/AlertGroup.d.ts +1 -1
- package/dist/components/Anchor/Anchor.d.ts +1 -1
- package/dist/components/ApprovalCard/ApprovalCard.d.ts +1 -1
- package/dist/components/AspectRatio/AspectRatio.d.ts +1 -1
- package/dist/components/AutoComplete/AutoComplete.d.ts +1 -1
- package/dist/components/Avatar/Avatar.d.ts +1 -1
- package/dist/components/AvatarGroup/AvatarGroup.d.ts +1 -1
- package/dist/components/BackTop/BackTop.d.ts +1 -1
- package/dist/components/Badge/Badge.d.ts +1 -1
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +1 -1
- package/dist/components/Button/Button.d.ts +1 -1
- package/dist/components/Calendar/Calendar.d.ts +1 -1
- package/dist/components/Card/Card.d.ts +1 -1
- package/dist/components/Carousel/Carousel.d.ts +1 -1
- package/dist/components/Cascader/Cascader.d.ts +1 -1
- package/dist/components/Chart/Chart.d.ts +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +1 -1
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +1 -1
- package/dist/components/CodeBlock/CodeBlock.d.ts +1 -1
- package/dist/components/Collapse/Collapse.d.ts +1 -1
- package/dist/components/ColorPicker/ColorPicker.d.ts +1 -1
- package/dist/components/Command/Command.d.ts +1 -1
- package/dist/components/Confirm/Confirm.d.ts +2 -2
- package/dist/components/ContextMenu/ContextMenu.d.ts +1 -1
- package/dist/components/CopyButton/CopyButton.d.ts +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +1 -1
- package/dist/components/Descriptions/Descriptions.d.ts +1 -1
- package/dist/components/DiffView/DiffView.d.ts +1 -1
- package/dist/components/Divider/Divider.d.ts +1 -1
- package/dist/components/Drawer/Drawer.d.ts +1 -1
- package/dist/components/Dropdown/Dropdown.d.ts +1 -1
- package/dist/components/Editor/Editor.d.ts +1 -1
- package/dist/components/Editor/tools/toolbar.d.ts +1 -1
- package/dist/components/EmptyState/EmptyState.d.ts +1 -1
- package/dist/components/Field/Field.d.ts +1 -1
- package/dist/components/FileUpload/FileUpload.d.ts +1 -1
- package/dist/components/FloatButton/FloatButton.d.ts +1 -1
- package/dist/components/Form/Form.d.ts +1 -1
- package/dist/components/Grid/Grid.d.ts +1 -1
- package/dist/components/Highlight/Highlight.d.ts +1 -1
- package/dist/components/HoverCard/HoverCard.d.ts +2 -2
- package/dist/components/Icon/Icon.d.ts +1 -1
- package/dist/components/Img/Img.d.ts +1 -1
- package/dist/components/InView/InView.d.ts +1 -1
- package/dist/components/InfiniteScroll/InfiniteScroll.d.ts +1 -1
- package/dist/components/Input/Input.d.ts +1 -1
- package/dist/components/InputNumber/InputNumber.d.ts +1 -1
- package/dist/components/JSONViewer/JSONViewer.d.ts +1 -1
- package/dist/components/Kanban/Kanban.d.ts +1 -1
- package/dist/components/Label/Label.d.ts +1 -1
- package/dist/components/Layout/Layout.d.ts +1 -1
- package/dist/components/Link/Link.d.ts +1 -1
- package/dist/components/List/List.d.ts +1 -1
- package/dist/components/Loading/Loading.d.ts +1 -1
- package/dist/components/LogViewer/LogViewer.d.ts +1 -1
- package/dist/components/Markdown/Markdown.d.ts +1 -1
- package/dist/components/Mentions/Mentions.d.ts +1 -1
- package/dist/components/Menu/Menu.d.ts +1 -1
- package/dist/components/Menubar/Menubar.d.ts +1 -1
- package/dist/components/MessageBubble/MessageBubble.d.ts +1 -1
- package/dist/components/Modal/Modal.d.ts +1 -1
- package/dist/components/NavMenu/NavMenu.d.ts +1 -1
- package/dist/components/Notification/Notification.d.ts +2 -2
- package/dist/components/PageHeader/PageHeader.d.ts +1 -1
- package/dist/components/Pagination/Pagination.d.ts +1 -1
- package/dist/components/PasswordInput/PasswordInput.d.ts +1 -1
- package/dist/components/PinInput/PinInput.d.ts +1 -1
- package/dist/components/Pipeline/Pipeline.d.ts +1 -1
- package/dist/components/Popconfirm/Popconfirm.d.ts +2 -2
- package/dist/components/Popover/Popover.d.ts +2 -2
- package/dist/components/ProgressBar/ProgressBar.d.ts +1 -1
- package/dist/components/QRCode/QRCode.d.ts +1 -1
- package/dist/components/RadioGroup/RadioGroup.d.ts +1 -1
- package/dist/components/Rate/Rate.d.ts +1 -1
- package/dist/components/Resizable/Resizable.d.ts +1 -1
- package/dist/components/Result/Result.d.ts +1 -1
- package/dist/components/Scrollbar/Scrollbar.d.ts +1 -1
- package/dist/components/SearchInput/SearchInput.d.ts +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +1 -1
- package/dist/components/Select/Select.d.ts +1 -1
- package/dist/components/Skeleton/Skeleton.d.ts +1 -1
- package/dist/components/Slider/Slider.d.ts +1 -1
- package/dist/components/Space/Space.d.ts +1 -1
- package/dist/components/Sparkline/Sparkline.d.ts +1 -1
- package/dist/components/StatCard/StatCard.d.ts +1 -1
- package/dist/components/Steps/Steps.d.ts +1 -1
- package/dist/components/Switch/Switch.d.ts +1 -1
- package/dist/components/Table/Table.d.ts +1 -1
- package/dist/components/Tabs/Tabs.d.ts +1 -1
- package/dist/components/Tag/Tag.d.ts +1 -1
- package/dist/components/TagsInput/TagsInput.d.ts +1 -1
- package/dist/components/Textarea/Textarea.d.ts +1 -1
- package/dist/components/ThemeSwitch/ThemeSwitch.d.ts +1 -1
- package/dist/components/Timeline/Timeline.d.ts +1 -1
- package/dist/components/Toast/Toast.d.ts +2 -2
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +1 -1
- package/dist/components/ToolCallCard/ToolCallCard.d.ts +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts +2 -2
- package/dist/components/Tour/Tour.d.ts +1 -1
- package/dist/components/Transfer/Transfer.d.ts +1 -1
- package/dist/components/Tree/Tree.d.ts +1 -1
- package/dist/components/TreeSelect/TreeSelect.d.ts +1 -1
- package/dist/components/Typography/Typography.d.ts +1 -1
- package/dist/components/VirtualList/VirtualList.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTable.d.ts +1 -1
- package/dist/components/Watermark/Watermark.d.ts +1 -1
- package/dist/components/index.js +12 -12
- package/dist/dev/index.js +1 -1
- package/dist/index.js +4 -4
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/ssr-page.d.ts +1 -1
- package/dist/ui/ssr.d.ts +1 -1
- package/dist/ui-dom/Confirm.d.ts +44 -0
- package/dist/ui-dom/Notification.d.ts +70 -0
- package/dist/ui-dom/Toast.d.ts +43 -0
- package/dist/ui-dom/index.d.ts +33 -0
- package/dist/ui-dom/index.js +18 -0
- package/dist/ui-dom/jsx-runtime.d.ts +4 -0
- package/dist/ui-dom/jsx-runtime.js +1 -0
- package/dist/ui-dom/popup-tracker.d.ts +36 -0
- package/dist/{client → ui-dom}/popup.d.ts +0 -11
- package/dist/ui-dom/registry.d.ts +39 -0
- package/dist/{client → ui-dom}/render.d.ts +2 -1
- package/dist/ui-dom/router.d.ts +66 -0
- package/dist/ui-dom/serve.d.ts +28 -0
- package/dist/ui-dom/ssr.d.ts +56 -0
- package/dist/{client → ui-dom}/types.d.ts +60 -0
- package/dist/{client → ui-dom}/ui.d.ts +2 -0
- package/dist/{client → ui-dom}/vnode.d.ts +13 -12
- package/docs/custom-components.md +2 -0
- package/docs/frontend-middleware.md +3 -1
- package/docs/frontend-ui-dom.md +165 -0
- package/docs/frontend.md +3 -1
- package/docs/realtime.md +2 -0
- package/docs/saas.md +2 -0
- package/package.json +7 -7
- package/dist/client/app.d.ts +0 -26
- package/dist/client/error-boundary.d.ts +0 -23
- package/dist/client/index.d.ts +0 -54
- package/dist/client/index.js +0 -6
- package/dist/client/registry.d.ts +0 -49
- package/dist/client/router.d.ts +0 -27
- package/dist/client/type-flow.test.d.ts +0 -7
- /package/dist/{client → ui-dom}/ai.d.ts +0 -0
- /package/dist/{client → ui-dom}/browser.d.ts +0 -0
- /package/dist/{client → ui-dom}/diff.d.ts +0 -0
- /package/dist/{client → ui-dom}/focus-trap.d.ts +0 -0
- /package/dist/{client → ui-dom}/hydration.d.ts +0 -0
- /package/dist/{client → ui-dom}/i18n.d.ts +0 -0
- /package/dist/{client → ui-dom}/locale/en_US.d.ts +0 -0
- /package/dist/{client → ui-dom}/locale/zh_CN.d.ts +0 -0
- /package/dist/{client → ui-dom}/middleware/api.d.ts +0 -0
- /package/dist/{client → ui-dom}/middleware/auth.d.ts +0 -0
- /package/dist/{client → ui-dom}/middleware/ws.d.ts +0 -0
- /package/dist/{client → ui-dom}/motion.d.ts +0 -0
- /package/dist/{client → ui-dom}/reactive.d.ts +0 -0
- /package/dist/{client → ui-dom}/route-match.d.ts +0 -0
- /package/dist/{client → ui-dom}/scroll-lock.d.ts +0 -0
- /package/dist/{client → ui-dom}/use-chat.d.ts +0 -0
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ npm install weifuwu # 一个依赖,完整应用栈
|
|
|
23
23
|
| 层 | 入口 | 能力 |
|
|
24
24
|
|----|------|------|
|
|
25
25
|
| 后端 | `weifuwu` | Trie 路由 / 中间件链 / serve / 自研 PG+Redis / SSR / GraphQL / WebSocket |
|
|
26
|
-
| 前端 | `weifuwu/
|
|
26
|
+
| 前端 | `weifuwu/ui-dom` | **UIRouter(纯路由 + ctx 注入链)+ uiServe(渲染运行时)+ SSR/hydration**——handler=异步组件 / 中间件两阶段 / ctx.params 对齐后端;**weifuwu/components 直接复用**(VNode 契约唯一来源 ui-dom,见 `docs/frontend-ui-dom.md`) |
|
|
27
27
|
| 组件 | `weifuwu/components` | 109 个 HTML 原语组件(表单/表格/弹层/AiChat…),引用 `--wf-*` 主题变量 |
|
|
28
28
|
| 样式 | `weifuwu/layout` | 57 布局原语 + 136 工具类 + 167 主题 Token,零自定义 CSS 文件 |
|
|
29
29
|
| SaaS 地基 | 随包内置 | rateLimit / email / userSystem / messager / queue / ai → `ctx.*` 一行接入 |
|
|
@@ -97,7 +97,7 @@ npm install weifuwu # 一个依赖,完整应用栈
|
|
|
97
97
|
|
|
98
98
|
**async 工厂组件** — `async (ctx) => (initProps, ctx) => (props) => VNode`:工厂层声明数据(`await ctx.data.get`)、mount 初始化状态(`$`)、render 输出视图。异步只在工厂边界,mount/render 保持同步;数据经闭包注入,写数据像写同步代码。三条纪律见[核心概念 · async 组件](#核心概念)。
|
|
99
99
|
|
|
100
|
-
**SPA/SSR/Hydration 统一透明** — 同一份路由定义(`
|
|
100
|
+
**SPA/SSR/Hydration 统一透明** — 同一份路由定义(`UIRouter`)一个组件三场景自动适配:后端 `ssrPage(router, { url })` 匹配即自动 SSR(完整 HTML + `__DATA__`),客户端 `uiServe(router, { root, hydrate: true })` 按 URL 同源匹配并收养服务端 HTML(不重建、无闪跳)。`ctx.data.get` 一个 API:SSR 预取 / hydration 命中(不重复请求)/ SPA 触发 fetch。服务端直接用 `.tsx`(`weifuwu/dev` Node loader),前后端同一 JSX 运行时。
|
|
101
101
|
|
|
102
102
|
**AI 是一等公民** — 自研 OpenAI 兼容协议(`design/ai-contract.md`)+ 零依赖流式客户端 + agent 工具循环 + HITL 人工审批 + embedding 向量化。后端 `ctx.ai` 一个入口:`chat()` / `stream()` / `agent()`(`stream(messages, { emit })` emitter 抽象——事件可接任意通道,`runToResult()` 结构化结果)/ `approve()` / `embed()` / `embedMany()`;前端 `ctx.ui.useChat()`(会话语义)+ `AiChat` 组件(标准对话界面)——流式 token / 工具调用卡 / 审批卡开箱即用,协议对页面完全透明,不用 ai-sdk。
|
|
103
103
|
|
|
@@ -119,15 +119,16 @@ npm install weifuwu # 一个依赖,完整应用栈
|
|
|
119
119
|
|
|
120
120
|
| 模式 | 适用场景 | 后端 | 客户端入口 |
|
|
121
121
|
|------|---------|------|-----------|
|
|
122
|
-
| **SPA** | 应用页(Dashboard、工具、后台) | HTML 外壳 | `
|
|
123
|
-
| **SSR + Hydration** | 内容页(博客、营销,需要 SEO/首屏) | `
|
|
122
|
+
| **SPA** | 应用页(Dashboard、工具、后台) | HTML 外壳 | `uiServe(router, { root: '#root' })` |
|
|
123
|
+
| **SSR + Hydration** | 内容页(博客、营销,需要 SEO/首屏) | `ssrPage(router)` 一行 | `uiServe(router, { root: '#root', hydrate: true })` |
|
|
124
124
|
|
|
125
125
|
### 先写共享部分(两种模式都一样)
|
|
126
126
|
|
|
127
127
|
```tsx
|
|
128
|
-
// routes.tsx ——
|
|
129
|
-
import
|
|
130
|
-
|
|
128
|
+
// routes.tsx —— 页面声明(前后端共用 UIRouter)
|
|
129
|
+
import { UIRouter, asyncComponent } from 'weifuwu/ui-dom'
|
|
130
|
+
|
|
131
|
+
const app = new UIRouter()
|
|
131
132
|
|
|
132
133
|
// async 工厂组件:await 数据 → 返回视图(两阶段:外层初始化,内层渲染)
|
|
133
134
|
const Home = asyncComponent(async (ctx) => {
|
|
@@ -136,7 +137,9 @@ const Home = asyncComponent(async (ctx) => {
|
|
|
136
137
|
(props) => <h1>{msg.msg}</h1>
|
|
137
138
|
})
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
app.get('/', async () => <Home />) // handler = 异步组件
|
|
141
|
+
|
|
142
|
+
export { app }
|
|
140
143
|
```
|
|
141
144
|
|
|
142
145
|
### 模式 A:纯 SPA
|
|
@@ -144,62 +147,67 @@ export const routes: RouteDef[] = [{ path: '/', component: Home }]
|
|
|
144
147
|
```ts
|
|
145
148
|
// server.ts
|
|
146
149
|
import { serve, Router, ui, cors } from 'weifuwu'
|
|
150
|
+
import { app } from './routes.tsx'
|
|
147
151
|
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
const router = new Router()
|
|
153
|
+
router.use(cors())
|
|
154
|
+
router.use(ui()) // 注入 ctx.ui.html / ctx.ui.js / ctx.ui.css
|
|
151
155
|
|
|
152
156
|
// SPA 外壳(空 root + 前端 bundle)
|
|
153
|
-
|
|
157
|
+
router.get('/', (req, ctx) => ctx.ui.html`
|
|
154
158
|
<!doctype html><html><body>
|
|
155
159
|
<div id="root"></div>
|
|
156
160
|
<script src="/static/app.js"></script>
|
|
157
161
|
</body></html>
|
|
158
162
|
`)
|
|
159
|
-
|
|
160
|
-
|
|
163
|
+
router.get('/static/app.js', (req, ctx) => ctx.ui.js('./src/client.ts'))
|
|
164
|
+
router.get('/api/hello', () => Response.json({ msg: 'world' }))
|
|
161
165
|
|
|
162
|
-
serve(
|
|
166
|
+
serve(router, { port: 3000 })
|
|
163
167
|
```
|
|
164
168
|
|
|
165
169
|
```ts
|
|
166
170
|
// src/client.ts —— 纯客户端渲染
|
|
167
|
-
import {
|
|
168
|
-
import {
|
|
171
|
+
import { uiServe } from 'weifuwu/ui-dom'
|
|
172
|
+
import { app } from './routes.tsx'
|
|
169
173
|
|
|
170
|
-
|
|
174
|
+
uiServe(app, { root: '#root' }) // 监听 location → 执行路由 → VDOM 落地
|
|
171
175
|
```
|
|
172
176
|
|
|
173
177
|
### 模式 B:SSR + Hydration(内容页/SEO)
|
|
174
178
|
|
|
175
|
-
同一份 `
|
|
179
|
+
同一份 `router`、同一个组件,差异只在**后端加 `ssrPage` 一行、客户端加 `hydrate` 参数**:
|
|
176
180
|
|
|
177
181
|
```ts
|
|
178
|
-
// server.ts —— 完整版(与模式 A 的差异:
|
|
179
|
-
import { serve, Router, ui,
|
|
180
|
-
import {
|
|
182
|
+
// server.ts —— 完整版(与模式 A 的差异:ssrPage + 一条样式路由)
|
|
183
|
+
import { serve, Router, ui, cors } from 'weifuwu'
|
|
184
|
+
import { ssrPage } from 'weifuwu/ui-dom'
|
|
185
|
+
import { app } from './routes.tsx'
|
|
181
186
|
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
187
|
+
const router = new Router()
|
|
188
|
+
router.use(cors())
|
|
189
|
+
router.use(ui())
|
|
185
190
|
|
|
186
|
-
// 路由级 SSR:GET
|
|
191
|
+
// 路由级 SSR:GET 匹配共享 router → 注入 ctx.params → await 组件工厂
|
|
187
192
|
// → 完整 HTML + __DATA__ + bundle/styles 引用(无需手写页面 handler)
|
|
188
|
-
|
|
193
|
+
router.get('*', async (req, ctx) => {
|
|
194
|
+
const { page } = await ssrPage(app, { url: req.url ?? '/' })
|
|
195
|
+
return ctx.ui.html(page)
|
|
196
|
+
})
|
|
189
197
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
router.get('/static/app.js', (req, ctx) => ctx.ui.js('./src/client.ts'))
|
|
199
|
+
router.get('/static/style.css', (req, ctx) => ctx.ui.css('./src/style.css'))
|
|
200
|
+
router.get('/api/hello', () => Response.json({ msg: 'world' }))
|
|
193
201
|
|
|
194
|
-
serve(
|
|
202
|
+
serve(router, { port: 3000 })
|
|
195
203
|
```
|
|
196
204
|
|
|
197
205
|
```ts
|
|
198
206
|
// src/client.ts —— 与模式 A 的唯一差异:hydrate: true(收养服务端 HTML,无闪跳)
|
|
199
|
-
import {
|
|
200
|
-
import {
|
|
207
|
+
import { uiServe } from 'weifuwu/ui-dom'
|
|
208
|
+
import { app } from './routes.tsx'
|
|
201
209
|
|
|
202
|
-
|
|
210
|
+
uiServe(app, { root: '#root', hydrate: true })
|
|
203
211
|
```
|
|
204
212
|
|
|
205
213
|
### 启动(两种模式都一样)
|
|
@@ -245,7 +253,7 @@ cd apps/agent-platform && npm run seed && npm run dev
|
|
|
245
253
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
246
254
|
<title>Weifuwu CDN 示例</title>
|
|
247
255
|
|
|
248
|
-
<!-- 组件样式(可选,如只用 weifuwu/
|
|
256
|
+
<!-- 组件样式(可选,如只用 weifuwu/ui-dom 则不需要) -->
|
|
249
257
|
<link
|
|
250
258
|
rel="stylesheet"
|
|
251
259
|
href="https://unpkg.com/weifuwu@latest/dist/components/style.css"
|
|
@@ -258,14 +266,14 @@ cd apps/agent-platform && npm run seed && npm run dev
|
|
|
258
266
|
<script type="importmap">
|
|
259
267
|
{
|
|
260
268
|
"imports": {
|
|
261
|
-
"weifuwu/
|
|
269
|
+
"weifuwu/ui-dom": "https://unpkg.com/weifuwu@latest/dist/ui-dom/index.js",
|
|
262
270
|
"weifuwu/components": "https://unpkg.com/weifuwu@latest/dist/components/index.js"
|
|
263
271
|
}
|
|
264
272
|
}
|
|
265
273
|
</script>
|
|
266
274
|
|
|
267
275
|
<script type="module">
|
|
268
|
-
import {
|
|
276
|
+
import { UIRouter, uiServe, h } from 'weifuwu/ui-dom'
|
|
269
277
|
import { Card, Button, Badge } from 'weifuwu/components'
|
|
270
278
|
|
|
271
279
|
// 组件 = (initProps, ctx) => (props) => VNode
|
|
@@ -291,7 +299,10 @@ cd apps/agent-platform && npm run seed && npm run dev
|
|
|
291
299
|
)
|
|
292
300
|
}
|
|
293
301
|
|
|
294
|
-
|
|
302
|
+
// 路由 + 渲染:监听 location → 执行 handler → VDOM 落地
|
|
303
|
+
const app = new UIRouter()
|
|
304
|
+
app.get('/', () => h(Counter, {}))
|
|
305
|
+
uiServe(app, { root: '#root' })
|
|
295
306
|
</script>
|
|
296
307
|
</body>
|
|
297
308
|
</html>
|
|
@@ -303,7 +314,7 @@ cd apps/agent-platform && npm run seed && npm run dev
|
|
|
303
314
|
|
|
304
315
|
| 资源 | CDN 地址 | 说明 |
|
|
305
316
|
|------|---------|------|
|
|
306
|
-
| `weifuwu/
|
|
317
|
+
| `weifuwu/ui-dom` | `https://unpkg.com/weifuwu@latest/dist/ui-dom/index.js` | 前端运行时(UIRouter, uiServe, h, 状态管理等) |
|
|
307
318
|
| `weifuwu/components` | `https://unpkg.com/weifuwu@latest/dist/components/index.js` | 102 个 UI 组件(Button, Card, Table, Modal, Icon 等) |
|
|
308
319
|
| `weifuwu/components` | `https://unpkg.com/weifuwu@latest/dist/components/style.css` | 组件 CSS + 167 个主题 Token + 57 个布局原语 + 136 个工具类 |
|
|
309
320
|
| 独立布局系统 | `https://unpkg.com/weifuwu@latest/dist/layout/weifuwu-layout.css` | 仅 CSS 布局,不依赖 JS |
|
|
@@ -322,7 +333,8 @@ cd apps/agent-platform && npm run seed && npm run dev
|
|
|
322
333
|
| `weifuwu` | **postgres** | PostgreSQL 客户端(自研 PG v3 协议)→ `ctx.sql` | Router, DATABASE_URL |
|
|
323
334
|
| `weifuwu` | **redis** | Redis 客户端(自研 RESP2 协议)→ `ctx.redis` | Router, REDIS_URL |
|
|
324
335
|
| `weifuwu` | **ui** | SSR 渲染 + esbuild JS/CSS 动态编译 → `ctx.ui` | Router |
|
|
325
|
-
| `weifuwu` | **
|
|
336
|
+
| `weifuwu/ui-dom` | **uiServe** | 渲染运行时:监听 location → 执行路由 → VDOM 落地(`hydrate: true` 收养 SSR HTML) | UIRouter |
|
|
337
|
+
| `weifuwu/ui-dom` | **ssrPage** | 路由级 SSR:匹配共享 router → 自动完整 HTML + `__DATA__` | Router, ui |
|
|
326
338
|
| `weifuwu` | **rateLimit** | 限流中间件(fixed/sliding,redis 多实例原子)→ `ctx.limit` | Router, redis |
|
|
327
339
|
| `weifuwu` | **email** | 邮件发送(Resend/SMTP 自研/自定义适配器)→ `ctx.email` | Router |
|
|
328
340
|
| `weifuwu` | **userSystem** | 用户系统(scrypt 密码哈希 + 混合会话 + 多租户感知)→ `ctx.user` / `ctx.auth` / `ctx.tenantId` + `/api/auth/*` | Router, postgres |
|
|
@@ -336,17 +348,16 @@ cd apps/agent-platform && npm run seed && npm run dev
|
|
|
336
348
|
| `weifuwu` | **ok / badRequest / …** | HTTP 响应辅助函数(ok/badRequest/... 等 12 个) | — |
|
|
337
349
|
| `weifuwu` | **parseBody** | JSON 请求体安全解析 | — |
|
|
338
350
|
| Router 方法 | **app.graphql()** | GraphQL 端点(支持 GraphiQL),Router 实例方法(无需单独 import) | Router |
|
|
339
|
-
| `weifuwu/
|
|
340
|
-
| `weifuwu/
|
|
341
|
-
| `weifuwu/
|
|
342
|
-
| `weifuwu/
|
|
343
|
-
| `weifuwu/
|
|
344
|
-
| `weifuwu/
|
|
345
|
-
| `weifuwu/
|
|
346
|
-
| `weifuwu/
|
|
347
|
-
| `weifuwu/
|
|
348
|
-
| `weifuwu/
|
|
349
|
-
| `weifuwu/components` | **113 个组件** | Button/Table/Modal/Confirm/Toast/... + `confirm()` / `toast()` 命令式中间件 | weifuwu/client |
|
|
351
|
+
| `weifuwu/ui-dom` | **UIRouter** | 纯路由 + ctx 注入链(`use` 中间件累积类型,对齐后端 `app.use`);handler=异步组件 | — |
|
|
352
|
+
| `weifuwu/ui-dom` | **uiServe** | 渲染运行时:监听 location → 执行路由 → VDOM diff/patch;`hydrate: true` 收养 SSR HTML | UIRouter |
|
|
353
|
+
| `weifuwu/ui-dom` | **asyncComponent** | async 工厂组件:工厂层声明数据,mount/render 同步(三条纪律见[核心概念](#核心概念)) | — |
|
|
354
|
+
| `weifuwu/ui-dom` | **ctx.data** | 数据管道:SSR 预取 / hydration 命中 / SPA fetch(`ctx.data.get`) | uiServe |
|
|
355
|
+
| `weifuwu/ui-dom` | **api / auth / ws** | HTTP 客户端 / 认证 / WebSocket 中间件 | — |
|
|
356
|
+
| `weifuwu/ui-dom` | **i18n** | 国际化中间件(运行时切换语言) | — |
|
|
357
|
+
| `weifuwu/ui-dom` | **ssrPage / serializeData** | 服务端渲染:SSR HTML + `__DATA__` 序列化(`ctx.params` 两端同源) | — |
|
|
358
|
+
| `weifuwu/ui-dom` | **useChat / AiChat 原语** | AI 会话(流式/工具调用/HITL) | — |
|
|
359
|
+
| `weifuwu/ui-dom` | **事件原语** | `usePopup` / `useDialog` / `usePresence` / `useInView` / `useScrollPosition` / `useGlobalKey` / `useDrag` / `useDragDrop` / `useAnimationEnd` / `useTween` / `useReducedMotion`(浏览器事件/动画统一入口,见 [docs/mobile.md](docs/mobile.md)) | — |
|
|
360
|
+
| `weifuwu/components` | **113 个组件** | Button/Table/Modal/Confirm/Toast/... + `confirm()` / `toast()` 命令式中间件 | weifuwu/ui-dom |
|
|
350
361
|
| `weifuwu/layout` | **CSS 布局** | 57 个布局原语 + 136 个工具类 + 167 个主题 Token(也支持 `weifuwu/layout/style.css`) | — |
|
|
351
362
|
|
|
352
363
|
---
|
|
@@ -358,7 +369,7 @@ cd apps/agent-platform && npm run seed && npm run dev
|
|
|
358
369
|
| 任务 | 用 | 位置 |
|
|
359
370
|
|------|-----|------|
|
|
360
371
|
| 起 HTTP 服务 + 路由 | `serve(app)` + `new Router()` + `app.get/post/...` | [docs/server.md](docs/server.md) |
|
|
361
|
-
| 渲染页面(SPA / SSR+hydrate) | `ui()` + `
|
|
372
|
+
| 渲染页面(SPA / SSR+hydrate) | `ui()` + `ssrPage(router)`;`uiServe(router, { root, hydrate })` | [docs/frontend-ui-dom.md](docs/frontend-ui-dom.md) · [docs/frontend.md](docs/frontend.md) |
|
|
362
373
|
| 数据持久化 | `postgres()` → `` ctx.sql`SELECT *` `` · `redis()` → `ctx.redis` | [docs/data.md](docs/data.md) |
|
|
363
374
|
| 数据管道(SSR 预取/hydration/SPA) | `ctx.data.get(key)` + `asyncComponent` | [docs/frontend.md](docs/frontend.md) |
|
|
364
375
|
| 用户注册/登录/会话/多租户 | `userSystem()` → `ctx.auth` + `/api/auth/*` | [docs/saas.md](docs/saas.md) |
|
|
@@ -378,6 +389,16 @@ cd apps/agent-platform && npm run seed && npm run dev
|
|
|
378
389
|
|
|
379
390
|
## 核心概念
|
|
380
391
|
|
|
392
|
+
### 三层形态(路由 / 组件 / 异步工厂)
|
|
393
|
+
|
|
394
|
+
| 层 | 签名 | 异步 | 生命周期 |
|
|
395
|
+
|----|------|------|---------|
|
|
396
|
+
| **UIHandler**(路由) | `async (location, ctx) => VNode` | ✅ 整体 | 每次路由变化执行 |
|
|
397
|
+
| **Component**(组件) | `(initProps, ctx) => (props) => VNode` | ❌ 同步 | mount 一次 + render 每次 |
|
|
398
|
+
| **AsyncFactory**(异步组件) | `async (ctx) => (initProps, ctx) => (props) => VNode` | ✅ 只工厂 | 工厂一次(WeakMap 缓存) |
|
|
399
|
+
|
|
400
|
+
异步只出现在两个边界——路由 handler(整页)和组件工厂(数据声明);**mount/render 永远同步**(SSR/hydration 两端一致性的根基)。`async (initProps, ctx) => ...` 是混合错形——渲染器不 await 同步组件,Promise 会被当 render 函数调用。
|
|
401
|
+
|
|
381
402
|
### 两阶段组件(新手必读:为什么是两层)
|
|
382
403
|
|
|
383
404
|
组件 = `(initProps, ctx) => (props) => VNode`——**外层 = 初始化(只执行一次),内层 = 渲染(每次状态/props 变化时执行)**。类比:外层是对象的构造函数,内层是它的 render 方法。
|
|
@@ -404,13 +425,16 @@ const Counter = (_init, ctx) => {
|
|
|
404
425
|
app.get('/users', (req, ctx) => { ctx.sql`SELECT *` })
|
|
405
426
|
// ctx 已注入 ctx.sql
|
|
406
427
|
|
|
407
|
-
前端:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
428
|
+
前端: const router = new UIRouter()
|
|
429
|
+
router.use(api({ baseURL: '/api' }))
|
|
430
|
+
router.use(auth())
|
|
431
|
+
router.get('/users', async (location, ctx) => h(UsersPage, {}))
|
|
432
|
+
uiServe(router, { root: '#root' })
|
|
411
433
|
// ctx 已注入 ctx.api, ctx.auth
|
|
412
434
|
```
|
|
413
435
|
|
|
436
|
+
前端 req = `window.location`(原生对象,不包装),res = `VNode`,`uiServe` = VDOM 落地——与后端 `Request → Response`、`serve(router)` 完全同构。
|
|
437
|
+
|
|
414
438
|
### 状态管理
|
|
415
439
|
|
|
416
440
|
| 模式 | 后端 | 前端 |
|
|
@@ -457,10 +481,10 @@ const UserProfile = asyncComponent(async (ctx) => {
|
|
|
457
481
|
| | SPA | SSR + Hydration |
|
|
458
482
|
|---|---|---|
|
|
459
483
|
| 适用 | 应用页(后台、工具、Dashboard) | 内容页(博客、营销,需要 SEO/首屏) |
|
|
460
|
-
| 后端 | HTML 外壳 | `
|
|
461
|
-
| 客户端 | `
|
|
484
|
+
| 后端 | HTML 外壳 | `ssrPage(router, { url })` 一行(自动完整 HTML + `__DATA__`) |
|
|
485
|
+
| 客户端 | `uiServe(router, { root: '#root' })` | `uiServe(router, { root: '#root', hydrate: true })` |
|
|
462
486
|
|
|
463
|
-
**怎么选**:默认 SPA;需要 SEO 或首屏即内容时用 SSR。两种模式可混合——一个 app 内 `
|
|
487
|
+
**怎么选**:默认 SPA;需要 SEO 或首屏即内容时用 SSR。两种模式可混合——一个 app 内 `ssrPage` 匹配共享 router,未匹配 `next()` 走普通 handler。
|
|
464
488
|
|
|
465
489
|
### Closeable 接口
|
|
466
490
|
|
|
@@ -488,7 +512,8 @@ README 只保留入门内容(设计理念 / 快速开始 / 核心概念 / 模
|
|
|
488
512
|
|
|
489
513
|
| 文档 | 内容 |
|
|
490
514
|
|------|------|
|
|
491
|
-
| [docs/frontend.md](docs/frontend.md) | 前端核心:
|
|
515
|
+
| [docs/frontend.md](docs/frontend.md) | 前端核心:UIRouter / 组件模型 / 状态管理 / 条件与列表 / ref / 类型(历史 client 版见 docs/frontend.md) |
|
|
516
|
+
| [docs/frontend-ui-dom.md](docs/frontend-ui-dom.md) | **ui-dom**:UIRouter 纯路由 + uiServe 渲染运行时 + ctx 注入链 + components 复用 + SSR/hydration(前端唯一运行时——weifuwu/client 已删除) |
|
|
492
517
|
| [docs/frontend-middleware.md](docs/frontend-middleware.md) | 前端中间件:router / api / auth / ws / i18n / ErrorBoundary / confirm / toast / ScrollLock / extendCtx |
|
|
493
518
|
| [docs/components.md](docs/components.md) | 组件库(113 个组件 + 使用示例 + 组件列表) |
|
|
494
519
|
| [docs/layout.md](docs/layout.md) | 布局系统:57 个布局原语 + 136 个工具类 + 167 个主题 Token |
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
* return () => h(AiChat, { chat: $ })
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
|
-
import type { Component } from '../../
|
|
22
|
-
import type { UseChatHandle, UiMessage } from '../../
|
|
21
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
22
|
+
import type { UseChatHandle, UiMessage } from '../../ui-dom/use-chat.ts';
|
|
23
23
|
import type { WfError, WfUsage } from '../../ai/types.ts';
|
|
24
24
|
export interface AiChatLabels {
|
|
25
25
|
send: string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 滚动侦听:ctx.ui.useScrollPosition(全局/容器 scroll 监听 + rAF 节流,内置方案)。
|
|
6
6
|
* 裁剪:嵌套滚动容器、滚动容器非视口(container 未提供时仅视口)、自动生成标题锚点。
|
|
7
7
|
*/
|
|
8
|
-
import type { Component } from '../../
|
|
8
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
9
9
|
export interface AnchorItem {
|
|
10
10
|
href: string;
|
|
11
11
|
title: any;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 裁剪(CS-05):不做分组/虚拟化候选(Select searchable 覆盖分组场景);
|
|
14
14
|
* 自定义渲染用 `renderOption` 透传。
|
|
15
15
|
*/
|
|
16
|
-
import type { Component } from '../../
|
|
16
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
17
17
|
export interface AutoCompleteOption {
|
|
18
18
|
value: string;
|
|
19
19
|
label?: any;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 用于群聊成员、协作人列表。
|
|
6
6
|
* 裁剪:不做 hover 展开 tooltip(见 roadmap)。
|
|
7
7
|
*/
|
|
8
|
-
import type { Component } from '../../
|
|
8
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
9
9
|
import { type AvatarProps } from '../Avatar/Avatar.ts';
|
|
10
10
|
export interface AvatarGroupItem {
|
|
11
11
|
name?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Component } from '../../
|
|
1
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
2
2
|
export type BadgeVariant = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'error';
|
|
3
3
|
export interface BadgeProps {
|
|
4
4
|
variant?: BadgeVariant;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* weifuwu/components — Chart
|
|
3
3
|
*/
|
|
4
|
-
import type { Component } from '../../
|
|
4
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
5
5
|
import type { DataPoint, ChartType, ChartOptions } from './chart-utils.ts';
|
|
6
6
|
export type { DataPoint, ChartType, ChartOptions };
|
|
7
7
|
export interface ChartProps {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* 声明式:基于 Modal 封装,footer 自带「取消 / 确定」按钮。
|
|
5
5
|
* 命令式:confirm() 中间件注入 ctx.confirm(),返回 Promise<boolean>。
|
|
6
6
|
*/
|
|
7
|
-
import type { Component } from '../../
|
|
8
|
-
import type { AppMiddleware } from '../../
|
|
7
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
8
|
+
import type { AppMiddleware } from '../../ui-dom/types.ts';
|
|
9
9
|
export interface ConfirmProps {
|
|
10
10
|
open?: boolean;
|
|
11
11
|
title?: string;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* 状态管理:闭包变量 + ctx.ui.render()
|
|
8
8
|
*/
|
|
9
|
-
import type { Component } from '../../
|
|
9
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
10
10
|
export type DatePickerMode = 'date' | 'datetime' | 'time' | 'range';
|
|
11
11
|
export interface DatePickerProps {
|
|
12
12
|
mode?: DatePickerMode;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 详情字段展示:label/value 栅格(<dl> 语义结构,屏幕阅读器友好)。
|
|
5
5
|
* 用于 Agent 配置展示、实体详情、订单信息等只读字段场景。
|
|
6
6
|
*/
|
|
7
|
-
import type { Component } from '../../
|
|
7
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
8
8
|
export interface DescriptionItem {
|
|
9
9
|
label: any;
|
|
10
10
|
value: any;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* usePopup 组合器:click 触发 + 受控 open + 外部点击/Escape(document 级,
|
|
5
5
|
* 弹层在 portal 中按 Escape 也能关)+ 定位/视口 clamp + portal。
|
|
6
6
|
*/
|
|
7
|
-
import type { Component } from '../../
|
|
7
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
8
8
|
export interface DropdownItem {
|
|
9
9
|
label: string;
|
|
10
10
|
value?: string;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 使用两阶段模型 + VDOM innerHTML 支持。
|
|
8
8
|
* 状态管理:闭包变量 + ctx.ui.render()
|
|
9
9
|
*/
|
|
10
|
-
import type { Component } from '../../
|
|
10
|
+
import type { Component } from '../../ui-dom/vnode.ts';
|
|
11
11
|
import type { EditorProps } from './tools/types.ts';
|
|
12
12
|
export type { EditorProps, ToolbarItem } from './tools/types.ts';
|
|
13
13
|
export declare const Editor: Component<EditorProps>;
|