CSR 与 SPA Fallback
Vext 默认页面模型是 SSR + hydration。CSR fallback 必须显式、范围化配置。
本页在已有全栈项目中,为 /app 增加客户端 shell,并验证它不会接管不符合条件的请求。Vext 负责交付 shell,客户端内部的路由规则仍由应用实现;配置 scope 不会自动安装或生成客户端 router。
什么时候使用 CSR
当某个路径范围在首个 shell 后由浏览器应用接管时,可以使用 client-router 子应用:
- 后台工作台
- 编辑器或仪表盘工具
- 内嵌产品控制台
- 某个 path prefix 下的复杂客户端导航
普通内容页仍然建议 SSR。
配置 Scope
先创建 shell 页面。示例只显示客户端路径,用来验证 shell 已在浏览器运行:
把下面的 frontend 配置合并进 src/config/default.ts,保留项目的其他配置:
对象配置中的 scopes[] 默认是空数组,省略配置不会接管未知路径。spaFallback: true 则是特殊简写,会建立 / 范围、index 页面作为 shell;它不是“仅开启但无 scope”。要关闭 fallback,可使用 spaFallback: false 或对象中的 enabled: false。
主示例保留 shell 的 SSR,随后由浏览器接管交互和内部路由;这不要求每个客户端路径都有独立的服务端页面。
空 shell 的挂载行为
ssr: false 会保留 document、资源和页面 payload,但不输出服务端页面 body。渲染结果记录实际挂载模式:CSR、clientOnly: true 和 buffered SSR 的 client fallback 使用 createRoot;完成 SSR 的页面使用 hydrateRoot。合法 SSR 组件返回 null 时仍属于 SSR,不按 root 是否为空判断。
可以将本例设为 ssr: false 来交付空 shell。验证首屏、事件更新和 Console,确认没有 hydration mismatch。保留 SSR 时,首次服务端与客户端输出仍须一致;浏览器专属逻辑放在 effect 中。
请求匹配
只有同时满足以下条件才 fallback:
- 请求路径位于某个 scope 内
(按路径段匹配,
/app不匹配/apple;重叠时优先最长 basePath) - 没有显式 API 或 route 处理该请求
- 没有匹配静态资源
- 请求方法为 GET 或 HEAD,解码后的路径没有扩展名
- 请求接受 HTML;
text/html、*/*或未提供 Accept 都会被视为接受 HTML - 全局
spaFallback.exclude和当前 scope 的exclude均未命中
明确请求 JSON 的未知路径不会返回 shell。默认全局排除 /api/**、/openapi.json、/docs/**、/_vext/docs/**;自定义全局数组会替换默认值,应保留项目需要的排除项。scope 的 exclude 只排除该 shell,并不定义 API:例如本例的 /app/api/missing 仍可能进入普通 HTML 404 错误页分支。要提供 API,应注册真实路由并使用匹配的请求语义。
若 shell 页面不存在或渲染失败,框架继续尝试其他 404 处理,不应把返回的任意 HTML 误认为成功命中 scope。选择与错误页规则见错误页与 Document。
混合 SSR 与 CSR
一个项目可以同时使用:
关键规则是每个 client-router 区域都有明确 base path 和 shell page。
验证范围
执行 npm run build,通过后启动 npm start -- --port 3000:
- 以 HTML 导航打开
/app/projects:状态 200,原始 HTML 已有Client workspace与Loading path...;浏览器加载脚本后显示当前路径,控制台无 hydration mismatch。 - 对
/app/projects发送Accept: application/json:应走 404,不返回 shell。 - 请求
/app/missing.js、/app/api/missing、/api/missing:均不应命中该 shell。 - 请求
/apple/projects:不在/app范围,应走 404。
如需复现上述限制,可将 scope 的 ssr 改为 false 后重新构建启动:原始 root 为空,浏览器虽然可能恢复显示,但应记录 mismatch,不能判为无错误通过。验证后恢复 ssr: true 并停止服务。若已有显式路由匹配测试路径,以显式路由结果为准;fallback 仅处理未匹配请求。