voidzero-dev / voidzero-dev/vite-plus

Cloudflare workerd SSR: React module duplication in HeadContent useContext when used with TanStack Start + @cloudflare/vite-plugin

オープン
#1,671 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Rust
スター
5.8k
フォーク
262
平均マージ
23時間 41分
マージ済み PR(30日)
138

説明

## 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 が 2 回インスタンス化されていないかに注目します。完了条件は、HeadContent とその後の SSR レンダリングが invalid-hook-call エラーなしで完了することです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
bun, react, typescript, vite
領域
build-system, cloud, frontend, tooling
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
静か
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。