@hitch42/applet 0.1.0-beta.9 → 0.1.1-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/_internal/client.js +120 -11
  2. package/dist/_internal/log-context.d.ts +34 -0
  3. package/dist/_internal/log-context.js +2 -0
  4. package/dist/_internal/server.js +112 -57
  5. package/dist/applet.js +12 -12
  6. package/dist/build-Bh_S5BUv.js +2 -0
  7. package/dist/{build-CAb26kMY.js → build-CEfFoIZZ.js} +1 -1
  8. package/dist/{ci-5qWl7lT3.js → ci-BKw14X2h.js} +14 -13
  9. package/dist/client.d.ts +2 -2
  10. package/dist/{contract-rP_eV9PK.d.ts → contract-CsUpTBe0.d.ts} +1 -1
  11. package/dist/{deploy-D_OFJ6-Q.js → deploy-wGYjwXrx.js} +139 -88
  12. package/dist/{generate-CBPnHoqX.js → generate-BEIYs17x.js} +54 -22
  13. package/dist/generate-Dox-OYt6.js +2 -0
  14. package/dist/headers-DkNr9MLJ.js +17 -0
  15. package/dist/index.d.ts +3 -2
  16. package/dist/index.js +2 -1
  17. package/dist/{init-tfzwuYnk.js → init-6oGPM46R.js} +10 -15
  18. package/dist/{load-config-BYSxDVAl.js → load-config-xEdTXs0y.js} +2 -2
  19. package/dist/log-context-zu8U9Sjm.js +73 -0
  20. package/dist/{login-C7RKmmTe.js → login-CUx3TmFQ.js} +1 -1
  21. package/dist/{logs-DgjgAxj2.js → logs-DSjuEN0Q.js} +20 -22
  22. package/dist/{manifest-DD_SGkS6.d.ts → manifest-C6_F4bL8.d.ts} +5 -1
  23. package/dist/{manifest-Bp87Uz0a.js → manifest-CJSL9GuC.js} +20 -4
  24. package/dist/{project-D6XHllmC.js → project-BRZGd6xq.js} +197 -16
  25. package/dist/query-cache-CXmAyLv3.js +82 -0
  26. package/dist/react.d.ts +2 -1
  27. package/dist/react.js +59 -39
  28. package/dist/{schedules-dhU1yyFr.js → schedules-C8_Svr4h.js} +1 -1
  29. package/dist/server.d.ts +8 -3
  30. package/dist/server.js +29 -8
  31. package/dist/telephony.d.ts +24 -4
  32. package/dist/telephony.js +135 -16
  33. package/dist/{variables-Bwnr7oxf.js → variables-DT5RyHdH.js} +13 -13
  34. package/dist/vite.d.ts +3 -60
  35. package/dist/vite.js +50 -15
  36. package/dist/{workflow-engine-MogejNfF.js → workflow-engine-BOTzURKM.js} +1 -7
  37. package/dist/{workspace-XVtM12ZC.js → workspace-D0dnnlxL.js} +33 -38
  38. package/package.json +13 -6
  39. package/scaffold/.agents/skills/hitch-applets/SKILL.md +29 -3
  40. package/scaffold/.agents/skills/hitch-applets/references/manifest.md +8 -0
  41. package/scaffold/.agents/skills/hitch-applets/references/markdown.md +2 -0
  42. package/scaffold/.agents/skills/hitch-applets/references/records.md +2 -0
  43. package/scaffold/.agents/skills/hitch-data/SKILL.md +2 -1
  44. package/scaffold/.agents/skills/hitch-data/references/attributes.md +7 -1
  45. package/scaffold/.agents/skills/hitch-data/references/limits.md +13 -13
  46. package/scaffold/.agents/skills/hitch-theory/SKILL.md +3 -2
  47. package/scaffold/.agents/skills/react-best-practices/SKILL.md +127 -0
  48. package/scaffold/.agents/skills/react-best-practices/rules/advanced-effect-event-deps.md +50 -0
  49. package/scaffold/.agents/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  50. package/scaffold/.agents/skills/react-best-practices/rules/advanced-init-once.md +42 -0
  51. package/scaffold/.agents/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
  52. package/scaffold/.agents/skills/react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
  53. package/scaffold/.agents/skills/react-best-practices/rules/async-defer-await.md +82 -0
  54. package/scaffold/.agents/skills/react-best-practices/rules/async-dependencies.md +48 -0
  55. package/scaffold/.agents/skills/react-best-practices/rules/async-parallel.md +24 -0
  56. package/scaffold/.agents/skills/react-best-practices/rules/bundle-analyzable-paths.md +42 -0
  57. package/scaffold/.agents/skills/react-best-practices/rules/bundle-barrel-imports.md +39 -0
  58. package/scaffold/.agents/skills/react-best-practices/rules/bundle-conditional.md +35 -0
  59. package/scaffold/.agents/skills/react-best-practices/rules/bundle-defer-third-party.md +46 -0
  60. package/scaffold/.agents/skills/react-best-practices/rules/bundle-dynamic-imports.md +38 -0
  61. package/scaffold/.agents/skills/react-best-practices/rules/bundle-preload.md +40 -0
  62. package/scaffold/.agents/skills/react-best-practices/rules/client-event-listeners.md +78 -0
  63. package/scaffold/.agents/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
  64. package/scaffold/.agents/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  65. package/scaffold/.agents/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
  66. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-function-results.md +58 -0
  67. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  68. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-storage.md +56 -0
  69. package/scaffold/.agents/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  70. package/scaffold/.agents/skills/react-best-practices/rules/js-early-exit.md +50 -0
  71. package/scaffold/.agents/skills/react-best-practices/rules/js-flatmap-filter.md +51 -0
  72. package/scaffold/.agents/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  73. package/scaffold/.agents/skills/react-best-practices/rules/js-index-maps.md +37 -0
  74. package/scaffold/.agents/skills/react-best-practices/rules/js-length-check-first.md +50 -0
  75. package/scaffold/.agents/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  76. package/scaffold/.agents/skills/react-best-practices/rules/js-request-idle-callback.md +104 -0
  77. package/scaffold/.agents/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  78. package/scaffold/.agents/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  79. package/scaffold/.agents/skills/react-best-practices/rules/rendering-activity.md +26 -0
  80. package/scaffold/.agents/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
  81. package/scaffold/.agents/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
  82. package/scaffold/.agents/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  83. package/scaffold/.agents/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
  84. package/scaffold/.agents/skills/react-best-practices/rules/rendering-resource-hints.md +81 -0
  85. package/scaffold/.agents/skills/react-best-practices/rules/rendering-script-defer-async.md +36 -0
  86. package/scaffold/.agents/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  87. package/scaffold/.agents/skills/react-best-practices/rules/rendering-usetransition-loading.md +43 -0
  88. package/scaffold/.agents/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  89. package/scaffold/.agents/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  90. package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  91. package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  92. package/scaffold/.agents/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
  93. package/scaffold/.agents/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
  94. package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
  95. package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo.md +44 -0
  96. package/scaffold/.agents/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  97. package/scaffold/.agents/skills/react-best-practices/rules/rerender-no-inline-components.md +75 -0
  98. package/scaffold/.agents/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  99. package/scaffold/.agents/skills/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
  100. package/scaffold/.agents/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  101. package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
  102. package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  103. package/scaffold/.agents/skills/tanstack-query/SKILL.md +136 -0
  104. package/scaffold/.agents/skills/tanstack-query/references/compositions/automatic-invalidation-after-mutations.md +124 -0
  105. package/scaffold/.agents/skills/tanstack-query/references/compositions/broadcast-realtime-and-multi-tab-synchronization.md +150 -0
  106. package/scaffold/.agents/skills/tanstack-query/references/compositions/compose-query-with-tanstack-router-and-start.md +248 -0
  107. package/scaffold/.agents/skills/tanstack-query/references/compositions/enforce-query-best-practices-with-eslint.md +167 -0
  108. package/scaffold/.agents/skills/tanstack-query/references/compositions/persist-offline-and-restore-caches.md +181 -0
  109. package/scaffold/.agents/skills/tanstack-query/references/compositions/query-data-and-forms.md +156 -0
  110. package/scaffold/.agents/skills/tanstack-query/references/core/build-query-abstractions.md +130 -0
  111. package/scaffold/.agents/skills/tanstack-query/references/core/cancel-queries-and-consume-abort-signals.md +176 -0
  112. package/scaffold/.agents/skills/tanstack-query/references/core/concurrent-optimistic-updates.md +135 -0
  113. package/scaffold/.agents/skills/tanstack-query/references/core/coordinate-query-execution.md +188 -0
  114. package/scaffold/.agents/skills/tanstack-query/references/core/design-query-keys-and-options.md +182 -0
  115. package/scaffold/.agents/skills/tanstack-query/references/core/fetch-and-observe-queries.md +193 -0
  116. package/scaffold/.agents/skills/tanstack-query/references/core/implement-optimistic-updates-and-cache-writes.md +168 -0
  117. package/scaffold/.agents/skills/tanstack-query/references/core/paginate-and-build-infinite-queries.md +188 -0
  118. package/scaffold/.agents/skills/tanstack-query/references/core/seed-placeholder-select-and-transform-data.md +188 -0
  119. package/scaffold/.agents/skills/tanstack-query/references/core/selectors-and-derived-state.md +145 -0
  120. package/scaffold/.agents/skills/tanstack-query/references/core/tune-defaults-freshness-retries-and-refetching.md +172 -0
  121. package/scaffold/.agents/skills/tanstack-query/references/core/understand-query-internals-and-observers.md +104 -0
  122. package/scaffold/.agents/skills/tanstack-query/references/core/write-mutations-and-invalidate-related-queries.md +183 -0
  123. package/scaffold/.agents/skills/tanstack-query/references/framework/debug-with-devtools.md +169 -0
  124. package/scaffold/.agents/skills/tanstack-query/references/framework/handle-status-and-errors.md +119 -0
  125. package/scaffold/.agents/skills/tanstack-query/references/framework/shape-data-and-render-efficiently.md +184 -0
  126. package/scaffold/.agents/skills/tanstack-query/references/framework/use-framework-adapter-reactivity.md +185 -0
  127. package/scaffold/.agents/skills/tanstack-query/references/framework/use-suspense-and-error-boundaries.md +208 -0
  128. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/migrate-major-versions-and-codemods.md +169 -0
  129. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/prefetch-and-remove-request-waterfalls.md +228 -0
  130. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/setup-query-client-and-providers.md +161 -0
  131. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/ssr-hydration-and-streaming.md +209 -0
  132. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/test-query-code.md +160 -0
  133. package/scaffold/.agents/skills/tanstack-router/SKILL.md +134 -0
  134. package/scaffold/.agents/skills/tanstack-router/references/compositions/router-query.md +412 -0
  135. package/scaffold/.agents/skills/tanstack-router/references/react-router.md +495 -0
  136. package/scaffold/.agents/skills/tanstack-router/references/router-core/auth-and-guards.md +495 -0
  137. package/scaffold/.agents/skills/tanstack-router/references/router-core/code-splitting.md +318 -0
  138. package/scaffold/.agents/skills/tanstack-router/references/router-core/data-loading.md +490 -0
  139. package/scaffold/.agents/skills/tanstack-router/references/router-core/index.md +158 -0
  140. package/scaffold/.agents/skills/tanstack-router/references/router-core/navigation.md +433 -0
  141. package/scaffold/.agents/skills/tanstack-router/references/router-core/not-found-and-errors.md +436 -0
  142. package/scaffold/.agents/skills/tanstack-router/references/router-core/path-params.md +383 -0
  143. package/scaffold/.agents/skills/tanstack-router/references/router-core/search-params.md +343 -0
  144. package/scaffold/.agents/skills/tanstack-router/references/router-core/ssr.md +462 -0
  145. package/scaffold/.agents/skills/tanstack-router/references/router-core/type-safety.md +493 -0
  146. package/scaffold/.agents/skills/tanstack-router/references/router-plugin.md +250 -0
  147. package/scaffold/.agents/skills/tanstack-router/references/virtual-file-routes.md +215 -0
  148. package/scaffold/.agents/skills/web-design-guidelines/SKILL.md +184 -0
  149. package/scaffold/.github/workflows/hitch.yml +1 -1
  150. package/scaffold/AGENTS.md +2 -2
  151. package/scaffold/applet/src/client/components/ui/alert.tsx +1 -1
  152. package/scaffold/applet/src/client/components/ui/button.tsx +1 -1
  153. package/scaffold/applet/src/client/components/ui/checkbox.tsx +1 -1
  154. package/scaffold/applet/src/client/components/ui/dialog.tsx +2 -2
  155. package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +2 -2
  156. package/scaffold/applet/src/client/components/ui/input-group.tsx +2 -2
  157. package/scaffold/applet/src/client/components/ui/select.tsx +2 -2
  158. package/scaffold/applet/src/client/components/ui/sheet.tsx +2 -2
  159. package/scaffold/applet/src/client/components/ui/spinner.tsx +2 -1
  160. package/scaffold/applet/src/client/components/ui/tabs.tsx +1 -1
  161. package/scaffold/applet/src/client/lib/utils.ts +1 -6
  162. package/scaffold/applet/src/client/styles/globals.css +2 -0
  163. package/dist/build-BfbTbt_r.js +0 -2
  164. package/dist/generate-BgepN4-b.js +0 -2
@@ -0,0 +1,462 @@
1
+ ---
2
+ name: ssr
3
+ description: >-
4
+ Non-streaming and streaming SSR, RouterClient/RouterServer,
5
+ renderRouterToString/renderRouterToStream, createRequestHandler,
6
+ defaultRenderHandler/defaultStreamHandler, HeadContent/Scripts
7
+ components, head route option (meta/links/styles/scripts),
8
+ ScriptOnce, automatic loader dehydration/hydration, memory
9
+ history on server, data serialization, document head management.
10
+ metadata:
11
+ type: sub-skill
12
+ library: tanstack-router
13
+ library_version: "1.171.15"
14
+ requires:
15
+ - router-core
16
+ - router-core/data-loading
17
+ sources:
18
+ - TanStack/router:docs/router/guide/ssr.md
19
+ - TanStack/router:docs/router/guide/document-head-management.md
20
+ - TanStack/router:docs/router/how-to/setup-ssr.md
21
+ ---
22
+
23
+ # SSR (Server-Side Rendering)
24
+
25
+ > **WARNING**: SSR APIs are experimental. They share internal implementations with TanStack Start and may change. **TanStack Start is the recommended way to do SSR in production** — use manual SSR setup only when integrating with an existing server.
26
+
27
+ > **CRITICAL**: TanStack Router is CLIENT-FIRST. Loaders run on the client by default. With SSR enabled, loaders run on BOTH client AND server. They are NOT server-only like Remix/Next.js loaders. See [router-core/data-loading](data-loading.md).
28
+
29
+ > **CRITICAL**: Do not generate Next.js patterns (`getServerSideProps`, App Router, server components) or Remix patterns (server-only loader exports). TanStack Router has its own SSR API.
30
+
31
+ ## Concepts
32
+
33
+ There are two SSR flavors:
34
+
35
+ - **Non-streaming**: Full page rendered on server, sent as one HTML response, then hydrated on client.
36
+ - **Streaming**: Critical first paint sent immediately; remaining content streamed incrementally as it resolves.
37
+
38
+ Key behaviors:
39
+
40
+ - Memory history is used automatically on the server (no `window`).
41
+ - Loader data is automatically dehydrated on the server and hydrated on the client.
42
+ - Data serialization supports `Date`, `Error`, `FormData`, and `undefined` out of the box.
43
+
44
+ ## Setup: Shared Router Factory
45
+
46
+ The router must be created identically on server and client. Export a factory function from a shared file:
47
+
48
+ ```tsx
49
+ // src/router.tsx
50
+ import { createRouter as createTanstackRouter } from "@tanstack/react-router";
51
+ import { routeTree } from "./routeTree.gen";
52
+
53
+ export function createRouter() {
54
+ return createTanstackRouter({ routeTree });
55
+ }
56
+
57
+ declare module "@tanstack/react-router" {
58
+ interface Register {
59
+ router: ReturnType<typeof createRouter>;
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Non-Streaming SSR
65
+
66
+ ### Server Entry (using `defaultRenderHandler`)
67
+
68
+ ```tsx
69
+ // src/entry-server.tsx
70
+ import { createRequestHandler, defaultRenderHandler } from "@tanstack/react-router/ssr/server";
71
+ import { createRouter } from "./router";
72
+
73
+ export async function render({ request }: { request: Request }) {
74
+ const handler = createRequestHandler({ request, createRouter });
75
+ return await handler(defaultRenderHandler);
76
+ }
77
+ ```
78
+
79
+ ### Server Entry (using `renderRouterToString` for custom wrappers)
80
+
81
+ ```tsx
82
+ // src/entry-server.tsx
83
+ import {
84
+ createRequestHandler,
85
+ renderRouterToString,
86
+ RouterServer,
87
+ } from "@tanstack/react-router/ssr/server";
88
+ import { createRouter } from "./router";
89
+
90
+ export function render({ request }: { request: Request }) {
91
+ const handler = createRequestHandler({ request, createRouter });
92
+
93
+ return handler(({ responseHeaders, router }) =>
94
+ renderRouterToString({
95
+ responseHeaders,
96
+ router,
97
+ children: <RouterServer router={router} />,
98
+ }),
99
+ );
100
+ }
101
+ ```
102
+
103
+ ### Client Entry
104
+
105
+ ```tsx
106
+ // src/entry-client.tsx
107
+ import { hydrateRoot } from "react-dom/client";
108
+ import { RouterClient } from "@tanstack/react-router/ssr/client";
109
+ import { createRouter } from "./router";
110
+
111
+ const router = createRouter();
112
+
113
+ hydrateRoot(document, <RouterClient router={router} />);
114
+ ```
115
+
116
+ ## Streaming SSR
117
+
118
+ ### Server Entry (using `defaultStreamHandler`)
119
+
120
+ ```tsx
121
+ // src/entry-server.tsx
122
+ import { createRequestHandler, defaultStreamHandler } from "@tanstack/react-router/ssr/server";
123
+ import { createRouter } from "./router";
124
+
125
+ export async function render({ request }: { request: Request }) {
126
+ const handler = createRequestHandler({ request, createRouter });
127
+ return await handler(defaultStreamHandler);
128
+ }
129
+ ```
130
+
131
+ ### Server Entry (using `renderRouterToStream` for custom wrappers)
132
+
133
+ ```tsx
134
+ // src/entry-server.tsx
135
+ import {
136
+ createRequestHandler,
137
+ renderRouterToStream,
138
+ RouterServer,
139
+ } from "@tanstack/react-router/ssr/server";
140
+ import { createRouter } from "./router";
141
+
142
+ export function render({ request }: { request: Request }) {
143
+ const handler = createRequestHandler({ request, createRouter });
144
+
145
+ return handler(({ request, responseHeaders, router }) =>
146
+ renderRouterToStream({
147
+ request,
148
+ responseHeaders,
149
+ router,
150
+ children: <RouterServer router={router} />,
151
+ }),
152
+ );
153
+ }
154
+ ```
155
+
156
+ Streaming is automatic — deferred data (unawaited promises from loaders) and streamed markup just work when using `defaultStreamHandler` or `renderRouterToStream`.
157
+
158
+ ## Document Head Management
159
+
160
+ Use the `head` route option to manage `<title>`, `<meta>`, `<link>`, and `<style>` tags. Render `<HeadContent />` in `<head>` and `<Scripts />` in `<body>`.
161
+
162
+ ### Root Route with Head
163
+
164
+ ```tsx
165
+ // src/routes/__root.tsx
166
+ import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
167
+
168
+ export const Route = createRootRoute({
169
+ head: () => ({
170
+ meta: [
171
+ { charSet: "UTF-8" },
172
+ { name: "viewport", content: "width=device-width, initial-scale=1.0" },
173
+ { title: "My App" },
174
+ ],
175
+ links: [{ rel: "icon", href: "/favicon.ico" }],
176
+ }),
177
+ component: RootComponent,
178
+ });
179
+
180
+ function RootComponent() {
181
+ return (
182
+ <html lang="en">
183
+ <head>
184
+ <HeadContent />
185
+ </head>
186
+ <body>
187
+ <Outlet />
188
+ <Scripts />
189
+ </body>
190
+ </html>
191
+ );
192
+ }
193
+ ```
194
+
195
+ ### Per-Route Head (Nested Deduplication)
196
+
197
+ Child route `title` and `meta` tags override parent tags with the same `name`/`property`:
198
+
199
+ ```tsx
200
+ // src/routes/posts/$postId.tsx
201
+ import { createFileRoute } from "@tanstack/react-router";
202
+
203
+ export const Route = createFileRoute("/posts/$postId")({
204
+ loader: async ({ params }) => {
205
+ const post = await fetchPost(params.postId);
206
+ return { post };
207
+ },
208
+ head: ({ loaderData }) => ({
209
+ meta: [
210
+ { title: loaderData.post.title },
211
+ { name: "description", content: loaderData.post.excerpt },
212
+ ],
213
+ }),
214
+ component: PostPage,
215
+ });
216
+
217
+ function PostPage() {
218
+ const { post } = Route.useLoaderData();
219
+ return <article>{post.content}</article>;
220
+ }
221
+ ```
222
+
223
+ ### SPA Head (No Full HTML Control)
224
+
225
+ For SPAs without server-rendered HTML, render `<HeadContent />` at the top of the component tree:
226
+
227
+ ```tsx
228
+ import { createRootRoute, HeadContent, Outlet } from "@tanstack/react-router";
229
+
230
+ const rootRoute = createRootRoute({
231
+ head: () => ({
232
+ meta: [{ title: "My SPA" }],
233
+ }),
234
+ component: () => (
235
+ <>
236
+ <HeadContent />
237
+ <Outlet />
238
+ </>
239
+ ),
240
+ });
241
+ ```
242
+
243
+ ## Body Scripts
244
+
245
+ Use `scripts` (separate from `head.scripts`) to inject scripts into `<body>` before the app entry point:
246
+
247
+ ```tsx
248
+ export const Route = createRootRoute({
249
+ scripts: () => [{ children: 'console.log("runs before hydration")' }],
250
+ });
251
+ ```
252
+
253
+ The `<Scripts />` component renders these. Place it at the end of `<body>`.
254
+
255
+ ## ScriptOnce for Pre-Hydration Scripts
256
+
257
+ `ScriptOnce` renders a `<script>` during SSR that executes immediately and self-removes. On client navigation, it does nothing (no duplicate execution).
258
+
259
+ ```tsx
260
+ import { ScriptOnce } from "@tanstack/react-router";
261
+
262
+ const themeScript = `(function() {
263
+ try {
264
+ const theme = localStorage.getItem('theme') || 'auto';
265
+ const resolved = theme === 'auto'
266
+ ? (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
267
+ : theme;
268
+ document.documentElement.classList.add(resolved);
269
+ } catch (e) {}
270
+ })();`;
271
+
272
+ function ThemeProvider({ children }: { children: React.ReactNode }) {
273
+ return (
274
+ <>
275
+ <ScriptOnce children={themeScript} />
276
+ {children}
277
+ </>
278
+ );
279
+ }
280
+ ```
281
+
282
+ If the script modifies the DOM (e.g., adds a class to `<html>`), use `suppressHydrationWarning` on the element:
283
+
284
+ ```tsx
285
+ <html lang="en" suppressHydrationWarning>
286
+ ```
287
+
288
+ ## Express Integration Example
289
+
290
+ `createRequestHandler` expects a Web API `Request` and returns a Web API `Response`. For Express, convert between formats:
291
+
292
+ ```tsx
293
+ // src/entry-server.tsx
294
+ import { pipeline } from "node:stream/promises";
295
+ import {
296
+ RouterServer,
297
+ createRequestHandler,
298
+ renderRouterToString,
299
+ } from "@tanstack/react-router/ssr/server";
300
+ import { createRouter } from "./router";
301
+ import type express from "express";
302
+
303
+ export async function render({ req, res }: { req: express.Request; res: express.Response }) {
304
+ const protocol = req.get("x-forwarded-proto") ?? req.protocol;
305
+ const host = req.get("x-forwarded-host") ?? req.get("host");
306
+ const url = new URL(req.originalUrl || req.url, `${protocol}://${host}`).href;
307
+
308
+ const request = new Request(url, {
309
+ method: req.method,
310
+ headers: (() => {
311
+ const headers = new Headers();
312
+ for (const [key, value] of Object.entries(req.headers)) {
313
+ headers.set(key, value as any);
314
+ }
315
+ return headers;
316
+ })(),
317
+ });
318
+
319
+ const handler = createRequestHandler({ request, createRouter });
320
+
321
+ const response = await handler(({ responseHeaders, router }) =>
322
+ renderRouterToString({
323
+ responseHeaders,
324
+ router,
325
+ children: <RouterServer router={router} />,
326
+ }),
327
+ );
328
+
329
+ res.status(response.status);
330
+ response.headers.forEach((value, name) => {
331
+ res.setHeader(name, value);
332
+ });
333
+
334
+ return pipeline(response.body as any, res);
335
+ }
336
+ ```
337
+
338
+ ## Common Mistakes
339
+
340
+ ### 1. HIGH: Using browser APIs in loaders without environment check
341
+
342
+ Loaders run on BOTH client and server with SSR. Browser-only APIs (`window`, `document`, `localStorage`) throw on the server.
343
+
344
+ ```tsx
345
+ // WRONG — crashes on server
346
+ loader: async () => {
347
+ const token = localStorage.getItem("token");
348
+ return fetchData(token);
349
+ };
350
+
351
+ // CORRECT — guard with environment check
352
+ loader: async () => {
353
+ const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
354
+ return fetchData(token);
355
+ };
356
+ ```
357
+
358
+ ### 2. MEDIUM: Using hash fragments for server-rendered content
359
+
360
+ Hash fragments (`#section`) are never sent to the server. Conditional rendering based on hash causes hydration mismatches.
361
+
362
+ ```tsx
363
+ // WRONG — server has no hash, client does → mismatch
364
+ component: () => {
365
+ const hash = window.location.hash
366
+ return hash === '#admin' ? <AdminPanel /> : <UserPanel />
367
+ }
368
+
369
+ // CORRECT — use search params for server-visible state
370
+ validateSearch: z.object({ view: fallback(z.enum(['admin', 'user']), 'user') }),
371
+ component: () => {
372
+ const { view } = Route.useSearch()
373
+ return view === 'admin' ? <AdminPanel /> : <UserPanel />
374
+ }
375
+ ```
376
+
377
+ ### 3. CRITICAL: Generating Next.js, Remix, or React Router DOM patterns
378
+
379
+ TanStack Router does NOT use `getServerSideProps`, `getStaticProps`, App Router `page.tsx`, Remix-style server-only `loader` exports, or anything from `react-router-dom`.
380
+
381
+ #### Wrong file structures
382
+
383
+ ```text
384
+ WRONG (Next.js Pages Router):
385
+ src/pages/index.tsx
386
+ src/pages/_app.tsx
387
+ src/pages/posts/[id].tsx
388
+
389
+ WRONG (Next.js App Router):
390
+ app/layout.tsx
391
+ app/page.tsx
392
+ app/posts/[id]/page.tsx
393
+
394
+ WRONG (Next.js custom App):
395
+ _app/index.tsx
396
+ pages/_app.tsx, pages/_document.tsx
397
+
398
+ CORRECT (TanStack Router file-based routing):
399
+ src/routes/__root.tsx
400
+ src/routes/index.tsx
401
+ src/routes/posts/$postId.tsx
402
+ ```
403
+
404
+ #### Wrong imports
405
+
406
+ ```tsx
407
+ // WRONG — react-router-dom is a different library
408
+ import { Link, useNavigate, BrowserRouter, Route, Routes } from "react-router-dom";
409
+
410
+ // WRONG — Next.js Link/router
411
+ import Link from "next/link";
412
+ import { useRouter } from "next/router"; // Pages Router
413
+ import { useRouter } from "next/navigation"; // App Router
414
+
415
+ // CORRECT — everything routing-related lives in @tanstack/react-router
416
+ import { Link, useNavigate, useRouter, useLocation, redirect } from "@tanstack/react-router";
417
+ ```
418
+
419
+ #### Wrong loader/data-fetching patterns
420
+
421
+ ```tsx
422
+ // WRONG — Next.js Pages Router
423
+ export async function getServerSideProps() {
424
+ return { props: { data: await fetchData() } };
425
+ }
426
+
427
+ // WRONG — Remix
428
+ export async function loader({ request }: LoaderFunctionArgs) {
429
+ return json({ data: await fetchData() });
430
+ }
431
+
432
+ // CORRECT — TanStack Router
433
+ export const Route = createFileRoute("/data")({
434
+ loader: async () => {
435
+ const data = await fetchData();
436
+ return { data };
437
+ },
438
+ component: DataPage,
439
+ });
440
+
441
+ function DataPage() {
442
+ const { data } = Route.useLoaderData();
443
+ return <div>{data}</div>;
444
+ }
445
+ ```
446
+
447
+ If you see `src/pages/`, `app/layout.tsx`, `react-router-dom`, or any of the above in agent output, the agent is generating for the wrong framework. The build will either fail or produce duplicate `/` routes that conflict at runtime.
448
+
449
+ ## Tension: Client-First Loaders vs SSR
450
+
451
+ TanStack Router loaders are client-first by design. When SSR is enabled, they run in both environments. This means:
452
+
453
+ - Browser APIs work by default (client-only) but break under SSR
454
+ - Database access does NOT belong in loaders (unlike Remix/Next) — use API routes
455
+ - For server-only data logic with SSR, use TanStack Start's server functions
456
+
457
+ See [router-core/data-loading](data-loading.md) for loader fundamentals.
458
+
459
+ ## Cross-References
460
+
461
+ - [router-core/data-loading](data-loading.md) — SSR changes where loaders execute
462
+ - [compositions/router-query](../compositions/router-query.md) — SSR dehydration/hydration with TanStack Query