feat(desktop): embed BoosAPI Desktop client as a subproject

Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as
a monorepo subdirectory under desktop/. Source only — node_modules,
dist, Cargo target and the upstream .git history are excluded.

desktop/ keeps its own independent Cargo workspace (desktop/src-tauri
with crates/*); it is not part of the backend boosapi crate, so a
`cargo check` at the metapi root still compiles only the backend. Build
the desktop app from desktop/src-tauri per desktop/README.md.

Note: app icons are still placeholder assets pending the final BoosAPI
logo. The updater signing keys live outside the repo and are not
included.
This commit is contained in:
boos
2026-06-22 11:32:57 +08:00
parent d9c78ecc73
commit e0a5f57793
2305 changed files with 449355 additions and 0 deletions
@@ -0,0 +1,150 @@
description: 在 Nuxt 3 SSR 中使用 markstream-vue,获得服务端 HTML、稳定 fallback,以及重节点的客户端增强。
---
# Nuxt 3 SSR 用法示例
> For the English version, see [nuxt-ssr.md](../nuxt-ssr.md).
`markstream-vue` 现在可以直接在 Nuxt SSR 中产出服务端 HTML。为了“能跑”而把整个 `<MarkdownRender>` 包进 `<ClientOnly>`,已经不是默认推荐做法。
当前的 SSR 模型是:
- 普通 markdown、HTML、链接、表格、脚注、图片会直接在服务端渲染。
- 代码块会先输出稳定的服务端 `<pre><code>` fallback,再在客户端增强成 Monaco。
- 数学公式在提供同步 KaTeX loader 时,可以直接在服务端输出真正的 KaTeX HTML。
- Mermaid、D2、Infographic 会先输出可读的 SSR fallback,再在客户端增强。
- scoped 自定义组件覆盖、自定义 node type、以及 `customHtmlTags` 也都能参与服务端渲染。
## 最小 SSR 页面
```vue
<script setup lang="ts">
import MarkdownRender from 'markstream-vue'
import { ref } from 'vue'
const markdown = ref(`
# 来自 Nuxt SSR 的问候
行内公式:$E = mc^2$
\`\`\`ts
export const greet = (name: string) => \`hello \${name}\`
\`\`\`
\`\`\`mermaid
graph TD
SSR --> Hydration
\`\`\`
`.trim())
</script>
<template>
<MarkdownRender :content="markdown" :final="true" />
</template>
```
这样首包就已经有服务端 HTML;重节点仍然会在 hydration 后增强,但不会先给你一个空壳。
## 服务端渲染数学公式
如果你希望 SSR 响应里直接带 KaTeX HTML,可以在 Nuxt 应用里注册同步 loader:
```ts
import katex from 'katex'
import { enableKatex } from 'markstream-vue'
enableKatex(() => katex)
```
如果没有这个 loader,数学公式也仍然是 SSR-safe,只是会稳定回退成可读原文。
## 预解析 nodes 与自定义组件
除了直接传 `content`,你也可以在 SSR 中传 `nodes`,或者配合 scoped custom components / trusted custom tags 一起使用。
```ts
import { setCustomComponents } from 'markstream-vue'
import { defineComponent, h } from 'vue'
setCustomComponents('docs-ssr', {
thinking: defineComponent({
props: {
node: { type: Object, required: true },
},
setup(props) {
return () => h('aside', { 'data-ssr-thinking': '1' }, String((props.node as any).content ?? ''))
},
}),
})
```
```vue
<template>
<MarkdownRender
custom-id="docs-ssr"
content="<thinking>服务端自定义标签</thinking>"
:custom-html-tags="['thinking']"
:final="true"
/>
</template>
```
如果你的服务端已经拿到了 AST,优先用 `nodes + final`,这样可以避免浏览器端重复解析,SSR 输出也更可控。
## 什么时候还需要 `<ClientOnly>`
通常不是给渲染器本身用的。
只有当你自己的页面逻辑本身依赖浏览器 API,或者你明确想让一整块区域跳过 SSR 时,才需要 `<ClientOnly>`。
## Nuxt playground
仓库里已经提供了完整的 Nuxt playground,路径是 `playground-nuxt/`:
```bash
pnpm install
pnpm play:nuxt
```
专门的 SSR 验证路由是:
- `/ssr-lab`
这个页面里有固定矩阵,用来覆盖:
- 基础 markdown + HTML 的 SSR
- 重节点的 SSR fallback
- hydration 后的增强路径
- 显式禁用增强时的稳定 fallback
- 自定义标签与 scoped override 的验证
## SSR 验收命令
Nuxt SSR 的验收 e2e 命令是:
```bash
pnpm test:e2e:nuxt-ssr
```
它会同时验证:
- `nuxt dev`
- `nuxt build && nuxt preview`
每种模式都会先检查 `/ssr-lab` 的原始 HTTP HTML,再打开浏览器验证 hydration、增强、reload 和路由往返后的稳定性。
## 库级 SSR 回归覆盖
仓库里还有一层直接针对渲染器的 `renderToString` 回归测试:
```bash
pnpm test --run test/ssr-render-to-string.test.ts test/ssr-import.test.ts
```
这层测试显式覆盖了:
- 轻节点 SSR 组件矩阵,例如 heading、paragraph、行内格式、link、list、table、footnote、admonition、`vmr_container`
- 独立的 `MarkdownCodeBlockNode` SSR shell
- 通过 `setCustomComponents` 做 scoped 内置覆盖
- 直接自定义 node type 的 SSR
- 通过 `customHtmlTags` 接入的可信自定义标签 SSR