voidzero-dev / voidzero-dev/vite-plus
Cloudflare workerd SSR: React module duplication in HeadContent useContext when used with TanStack Start + @cloudflare/vite-plugin
- 主要语言
- Rust
- 星标
- 5.8k
- 派生
- 262
- 平均合并
- 23 小时 18 分钟
- 30 天内合并 PR
- 139
描述
## Setup
- `vite-plus` (alias `vite` → `@voidzero-dev/vite-plus-core`) `0.1.22`
- `@cloudflare/vite-plugin` `^1.37.2` (workerd SSR environment)
- `@tanstack/react-start` `^1.168.10` + `@tanstack/react-router` `^1.170.7`
- React 19, `@vitejs/plugin-react` `^6.0.2`
- bun workspaces, single app uses TanStack Start
`vite.config.ts` mirrors the working garden setup exactly (vanilla Vite 8 + same `environments.ssr.optimizeDeps.include` list + same plugin order):
\`\`\`ts
export default defineConfig({
resolve: { tsconfigPaths: true, dedupe: ["react", "react-dom"] },
environments: {
ssr: {
optimizeDeps: {
include: [
"react", "react/jsx-runtime", "react/jsx-dev-runtime",
"react-dom", "react-dom/server",
"@tanstack/react-router > @tanstack/react-store",
],
},
},
},
plugins: [
cloudflare({ viteEnvironment: { name: "ssr" } }),
agents(),
tailwindcss(),
tanstackStart(),
viteReact(),
],
});
\`\`\`
## What happens
SSR shell render of \`HeadContent\` crashes with React invalid-hook-call:
\`\`\`
TypeError: Cannot read properties of null (reading 'useContext')
at exports.useContext (deps_ssr/react.js?v=…:706)
at useRouter (@tanstack/react-router/src/useRouter.tsx:20)
at useTags (@tanstack/react-router/src/headContentUtils.tsx:213)
at HeadContent (@tanstack/react-router/src/HeadContent.dev.tsx:22)
\`\`\`
i.e. the classic two-copies-of-React-in-workerd-SSR situation that cloudflare/workers-sdk#11825 describes. Browser ends up on the JSON 500 page (\`{"status":500,"message":"HTTPError"}\`).
The exact same source tree + the exact same config, run on **vanilla Vite 8** in another project (https://github.com/voidzero-dev/garden parallel — its \`apps/web\` works fine), renders cleanly.
## Comparison
| | vanilla Vite 8 (garden) | vite-plus-core 0.1.22 (this repo) |
|---|---|---|
| Same vite.config | works | 500 with useContext null in HeadContent |
| Same plugin order | works | broken |
| Same SSR optimizeDeps.include | works | broken |
Switching this repo's catalog alias to vanilla Vite 8 doesn't fully fix it either — first \`/\` render works, but on any subsequent SSR render of the route (HMR reload, client navigate, etc.) the same useContext null surfaces.
## Suspicion
`@voidzero-dev/vite-plus-core` ships its own (rolldown-backed?) Vite that handles \`environments.ssr.optimizeDeps\` differently from upstream Vite's dep optimizer, so the React module the workerd runner ends up with isn't the same instance the route bundle imports. This trips every provider hook downstream (`useContext` in `HeadContent`, `useEffect` in `QueryClientProvider`, etc.).
Repro repo: I can put one up if helpful — but the diff against the existing TanStack Start cloudflare example is essentially "swap upstream Vite for the vite-plus-core alias and add `@cloudflare/vite-plugin`".
## Related
- https://github.com/cloudflare/workers-sdk/issues/11825
- https://github.com/TanStack/router/issues/5208
贡献指南
调研方向
使用提供的 vite.config.ts 和 TanStack Start Cloudflare SSR 设置重现失败,然后将其与正常工作的 vanilla Vite 8 garden 示例进行比较。首先跟踪 environments.ssr.optimizeDeps 和 workerd SSR 模块加载,重点确认 React 是否被实例化了两次。完成标准是 HeadContent 及后续 SSR 渲染都能在没有 invalid-hook-call 错误的情况下完成。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- bun, react, typescript, vite
- 领域
- build-system, cloud, frontend, tooling
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 48/100