fix: SSR invariant dehydration errors with bun
Related: https://github.com/TanStack/router/issues/3989
The script assigned to __TSR_SSR__.dehydrated appears outside the </html> tag. When the entry script /_build/assets/client-BJoNZ2zg.js is cached locally by the browser, even if the entry script is async, the script outside the html may still be executed after the entry script.
https://github.com/TanStack/router/blob/72ffeb4d4ae23a30859b9c7b8a3164535d5f2b85/packages/start-server-core/src/transformStreamWithRouter.ts#L171
Problems occur when text is complete HTML
https://github.com/TanStack/router/blob/72ffeb4d4ae23a30859b9c7b8a3164535d5f2b85/packages/start-server-core/src/transformStreamWithRouter.ts#L174-L175
https://github.com/TanStack/router/blob/72ffeb4d4ae23a30859b9c7b8a3164535d5f2b85/packages/start-server-core/src/transformStreamWithRouter.ts#L190
bodyEndMatch is assigned before the !headStarted branch processes chunkString.
https://github.com/TanStack/router/blob/72ffeb4d4ae23a30859b9c7b8a3164535d5f2b85/packages/start-server-core/src/transformStreamWithRouter.ts#L216
The length of bodyEndIndex obtained here will exceed the length of the modified chunkString, resulting in <script> being appended after </html>
The solution is make sure hydrate is executed after TSR_SSR.dehydrated is assigned a value by other means.
View your CI Pipeline Execution ↗ for commit 846bf44fa7ca506adbd31ae9e8e8fbd1e0a287b8.
| Command | Status | Duration | Result |
|---|---|---|---|
nx affected --targets=test:eslint,test:unit,tes... |
✅ Succeeded | 1m 37s | View ↗ |
☁️ Nx Cloud last updated this comment at 2025-05-25 09:36:29 UTC
More templates
- tanstack-router-react-example-authenticated-routes
- tanstack-router-react-example-authenticated-routes-firebase
- tanstack-router-react-example-basic
- tanstack-router-react-example-basic-default-search-params
- tanstack-router-react-example-basic-devtools-panel
- tanstack-router-react-example-basic-file-based
- tanstack-router-react-example-basic-non-nested-devtools
- tanstack-router-react-example-react-query
- tanstack-router-react-example-basic-react-query-file-based
- tanstack-router-react-example-basic-ssr-file-based
- tanstack-router-react-example-basic-ssr-streaming-file-based
- tanstack-router-react-example-basic-virtual-file-based
- tanstack-router-react-example-basic-virtual-inside-file-based
- tanstack-router-react-example-deferred-data
- tanstack-router-react-example-kitchen-sink
- tanstack-router-react-example-kitchen-sink-file-based
- tanstack-router-react-example-kitchen-sink-react-query
- tanstack-router-react-example-kitchen-sink-react-query-file-based
- tanstack-router-react-example-large-file-based
- tanstack-router-react-example-location-masking
- tanstack-router-react-example-navigation-blocking
- tanstack-router-react-example-quickstart
- tanstack-router-react-example-quickstart-esbuild-file-based
- tanstack-router-react-example-quickstart-file-based
- tanstack-router-react-example-quickstart-rspack-file-based
- tanstack-router-react-example-quickstart-webpack-file-based
- router-monorepo-react-query
- router-mono-simple
- router-mono-simple-lazy
- tanstack-router-react-example-scroll-restoration
- tanstack-search-validator-adapters
- tanstack-start-example-bare
- tanstack-start-example-basic
- tanstack-start-example-basic-auth
- tanstack-start-example-basic-react-query
- tanstack-start-example-basic-rsc
- tanstack-start-example-basic-static
- tanstack-start-example-clerk-basic
- tanstack-start-example-convex-trellaux
- tanstack-start-example-counter
- tanstack-start-example-large
- tanstack-start-example-material-ui
- tanstack-start-example-supabase-basic
- tanstack-start-example-trellaux
- tanstack-start-example-workos
- tanstack-router-react-example-view-transitions
- tanstack-router-react-example-with-framer-motion
- tanstack-router-react-example-with-trpc
- tanstack-router-react-example-with-trpc-react-query
- tanstack-router-solid-example-basic
- tanstack-router-solid-example-basic-devtools-panel
- tanstack-router-solid-example-basic-file-based
- tanstack-router-solid-example-basic-non-nested-devtools
- tanstack-router-solid-example-basic-solid-query
- tanstack-router-solid-example-basic-solid-query-file-based
- tanstack-router-solid-example-kitchen-sink-file-based
- tanstack-router-solid-example-quickstart-file-based
- tanstack-solid-start-example-bare
- tanstack-solid-start-example-basic
@tanstack/arktype-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4228
@tanstack/directive-functions-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4228
@tanstack/history
npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4228
@tanstack/react-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4228
@tanstack/eslint-plugin-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4228
@tanstack/react-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4228
@tanstack/react-router-with-query
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4228
@tanstack/react-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4228
@tanstack/react-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4228
@tanstack/react-start-config
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-config@4228
@tanstack/react-start-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4228
@tanstack/react-start-router-manifest
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-router-manifest@4228
@tanstack/react-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4228
@tanstack/router-cli
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4228
@tanstack/router-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4228
@tanstack/router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4228
@tanstack/router-devtools-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4228
@tanstack/router-generator
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4228
@tanstack/router-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4228
@tanstack/router-utils
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4228
@tanstack/router-vite-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4228
@tanstack/server-functions-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4228
@tanstack/solid-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4228
@tanstack/solid-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4228
@tanstack/solid-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4228
@tanstack/solid-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4228
@tanstack/solid-start-config
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-config@4228
@tanstack/solid-start-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4228
@tanstack/solid-start-router-manifest
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-router-manifest@4228
@tanstack/solid-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4228
@tanstack/start
npm i https://pkg.pr.new/TanStack/router/@tanstack/start@4228
@tanstack/start-api-routes
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-api-routes@4228
@tanstack/start-client-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4228
@tanstack/start-config
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-config@4228
@tanstack/start-server-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4228
@tanstack/start-server-functions-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4228
@tanstack/start-server-functions-fetcher
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4228
@tanstack/start-server-functions-handler
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-handler@4228
@tanstack/start-server-functions-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4228
@tanstack/start-server-functions-ssr
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-ssr@4228
@tanstack/valibot-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4228
@tanstack/virtual-file-routes
npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4228
@tanstack/zod-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4228
commit: 846bf44
I think it would be better if ensure that all tsr-once is before the entry script
I think it would be better if ensure that all tsr-once is before the entry script
that's not possible as values might stream in later
how can I reproduce the issue locally?
how can I reproduce the issue locally?
For example:
cd example/react/start-material-ui
Update app.config.ts set server.preset = 'bun'
pnpm build
bun run .output/server/index.mjs
Open "localhost:3000" and enter F12 to switch the throttling to 3G
Tap reload button on browser navigation bar, after reloading for about a dozen times (client entry scripts cached in memory), Invariant failed started to appear.
Even if tsr-once is in html, Invariant failed will still appear. So I think if this script is before client entry script, the problem should be solved. Or the other way to make sure hydrate is executed after __TSR_SSR__.dehydrated is assigned a value by other means.
Change script loading attribute from async to defer seems to solve this problem
i found the issue, a synchronization error when injecting the scripts. I'll fix this as part of a rewrite of this section.
very thankful