@tanstack/react-router 1.121.39 → 1.121.41
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.
- package/dist/cjs/link.cjs +1 -0
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/esm/link.js +1 -0
- package/dist/esm/link.js.map +1 -1
- package/dist/llms/rules/guide.d.ts +1 -1
- package/dist/llms/rules/guide.js +104 -124
- package/package.json +3 -3
- package/src/link.tsx +1 -0
package/dist/llms/rules/guide.js
CHANGED
|
@@ -5182,6 +5182,9 @@ export const Route = createFileRoute('/search')({
|
|
|
5182
5182
|
|
|
5183
5183
|
# SSR
|
|
5184
5184
|
|
|
5185
|
+
> [!WARNING]
|
|
5186
|
+
> While every effort has been made to separate these APIs from changes to Tanstack Start, there are underlying shared implementations internally. Therefore these can be subject to change and should be regarded as experimental until Start reaches stable status.
|
|
5187
|
+
|
|
5185
5188
|
Server Side Rendering (SSR) is the process of rendering a component on the server and sending the HTML markup to the client. The client then hydrates the markup into a fully interactive component.
|
|
5186
5189
|
|
|
5187
5190
|
There are usually two different flavors of SSR to be considered:
|
|
@@ -5200,21 +5203,36 @@ Non-Streaming server-side rendering is the classic process of rendering the mark
|
|
|
5200
5203
|
|
|
5201
5204
|
To implement non-streaming SSR with TanStack Router, you will need the following utilities:
|
|
5202
5205
|
|
|
5203
|
-
- \`
|
|
5204
|
-
- e.g. \`<
|
|
5205
|
-
- Rendering this component in your server entry will render your application and also automatically handle application-level hydration/dehydration and implement the \`Wrap\` component option on \`Router\`
|
|
5206
|
-
- \`StartClient\` from \`@tanstack/react-start\`
|
|
5207
|
-
- e.g. \`<StartClient router={router} />\`
|
|
5206
|
+
- \`RouterClient\` from \`@tanstack/react-router\`
|
|
5207
|
+
- e.g. \`<RouterClient router={router} />\`
|
|
5208
5208
|
- Rendering this component in your client entry will render your application and also automatically implement the \`Wrap\` component option on \`Router\`
|
|
5209
|
+
- And, either:
|
|
5210
|
+
- \`defaultRenderHandler\` from \`@tanstack/react-router\`
|
|
5211
|
+
- This will render your application in your server entry and also automatically handle application-level hydration/dehydration and also automatically implement the RouterServer component.
|
|
5212
|
+
or:
|
|
5213
|
+
- \`renderRouterToString\` from \`@tanstack/react-router\`
|
|
5214
|
+
- This differs from defaultRenderHandler in that it allows you to manually specify the \`Wrap\` component option on \`Router\` together with any other providers you may need to wrap it with.
|
|
5215
|
+
- \`RouterServer\` from \`@tanstack/react-router\`
|
|
5216
|
+
- This implements the \`Wrap\` component option on \`Router\`
|
|
5217
|
+
|
|
5218
|
+
### Automatic Server History
|
|
5219
|
+
|
|
5220
|
+
On the client, Router defaults to using an instance of \`createBrowserHistory\`, which is the preferred type of history to use on the client. On the server, however, you will want to use an instance of \`createMemoryHistory\` instead. This is because \`createBrowserHistory\` uses the \`window\` object, which does not exist on the server. This is handled automatically for you in the RouterServer component.
|
|
5221
|
+
|
|
5222
|
+
### Automatic Loader Dehydration/Hydration
|
|
5223
|
+
|
|
5224
|
+
Resolved loader data fetched by routes is automatically dehydrated and rehydrated by TanStack Router so long as you complete the standard SSR steps outlined in this guide.
|
|
5225
|
+
|
|
5226
|
+
⚠️ If you are using deferred data streaming, you will also need to ensure that you have implemented the [SSR Streaming & Stream Transform](#streaming-ssr) pattern near the end of this guide.
|
|
5227
|
+
|
|
5228
|
+
For more information on how to utilize data loading, see the [Data Loading](../data-loading.md) guide.
|
|
5209
5229
|
|
|
5210
5230
|
### Router Creation
|
|
5211
5231
|
|
|
5212
5232
|
Since your router will exist both on the server and the client, it's important that you create your router in a way that is consistent between both of these environments. The easiest way to do this is to expose a \`createRouter\` function in a shared file that can be imported and called by both your server and client entry files.
|
|
5213
5233
|
|
|
5214
|
-
- \`src/router.tsx\`
|
|
5215
|
-
|
|
5216
5234
|
\`\`\`tsx
|
|
5217
|
-
|
|
5235
|
+
// src/router.tsx
|
|
5218
5236
|
import { createRouter as createTanstackRouter } from '@tanstack/react-router'
|
|
5219
5237
|
import { routeTree } from './routeTree.gen'
|
|
5220
5238
|
|
|
@@ -5229,153 +5247,131 @@ declare module '@tanstack/react-router' {
|
|
|
5229
5247
|
}
|
|
5230
5248
|
\`\`\`
|
|
5231
5249
|
|
|
5232
|
-
|
|
5250
|
+
### Rendering the Application on the Server
|
|
5251
|
+
|
|
5252
|
+
Now that you have a router instance that has loaded all of the critical data for the current URL, you can render your application on the server:
|
|
5233
5253
|
|
|
5234
|
-
|
|
5254
|
+
using \`defaultRenderToString\`
|
|
5235
5255
|
|
|
5236
5256
|
\`\`\`tsx
|
|
5257
|
+
// src/entry-server.tsx
|
|
5258
|
+
import {
|
|
5259
|
+
createRequestHandler,
|
|
5260
|
+
defaultRenderToString,
|
|
5261
|
+
} from '@tanstack/react-router/ssr/server'
|
|
5237
5262
|
import { createRouter } from './router'
|
|
5238
5263
|
|
|
5239
|
-
export async function render(
|
|
5240
|
-
const
|
|
5264
|
+
export async function render({ request }: { request: Request }) {
|
|
5265
|
+
const handler = createRequestHandler({ request, createRouter })
|
|
5266
|
+
|
|
5267
|
+
return await handler(defaultRenderToString)
|
|
5241
5268
|
}
|
|
5242
5269
|
\`\`\`
|
|
5243
5270
|
|
|
5244
|
-
|
|
5271
|
+
using \`renderRouterToString\`
|
|
5245
5272
|
|
|
5246
5273
|
\`\`\`tsx
|
|
5274
|
+
// src/entry-server.tsx
|
|
5275
|
+
import {
|
|
5276
|
+
createRequestHandler,
|
|
5277
|
+
renderRouterToString,
|
|
5278
|
+
RouterServer,
|
|
5279
|
+
} from '@tanstack/react-router/ssr/server'
|
|
5247
5280
|
import { createRouter } from './router'
|
|
5248
5281
|
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
### Server History
|
|
5253
|
-
|
|
5254
|
-
On the client, Router defaults to using an instance of \`createBrowserHistory\`, which is the preferred type of history to use on the client. On the server, however, you will want to use an instance of \`createMemoryHistory\` instead. This is because \`createBrowserHistory\` uses the \`window\` object, which does not exist on the server.
|
|
5255
|
-
|
|
5256
|
-
> 🧠 Make sure you initialize your memory history with the server URL that is being rendered.
|
|
5282
|
+
export function render({ request }: { request: Request }) {
|
|
5283
|
+
const handler = createRequestHandler({ request, createRouter })
|
|
5257
5284
|
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5285
|
+
return handler(({ request, responseHeaders, router }) =>
|
|
5286
|
+
renderRouterToString({
|
|
5287
|
+
request,
|
|
5288
|
+
responseHeaders,
|
|
5289
|
+
router,
|
|
5290
|
+
children: <RouterServer router={router} />,
|
|
5291
|
+
}),
|
|
5292
|
+
)
|
|
5293
|
+
}
|
|
5266
5294
|
\`\`\`
|
|
5267
5295
|
|
|
5268
|
-
|
|
5296
|
+
NOTE: The createRequestHandler method requires a web api standard Request object, while the handler method will return a web api standard Response promise.
|
|
5269
5297
|
|
|
5270
|
-
|
|
5298
|
+
Should you be using a server framework like Express that uses its own Request and Response objects you would need to convert from the one to the other. Please have a look at the examples for how such an implementation might look like.
|
|
5271
5299
|
|
|
5272
|
-
|
|
5273
|
-
router.update({
|
|
5274
|
-
history: memoryHistory,
|
|
5275
|
-
})
|
|
5276
|
-
\`\`\`
|
|
5300
|
+
## Rendering the Application on the Client
|
|
5277
5301
|
|
|
5278
|
-
|
|
5302
|
+
On the client, things are much simpler.
|
|
5279
5303
|
|
|
5280
|
-
|
|
5304
|
+
- Create your router instance
|
|
5305
|
+
- Render your application using the \`<RouterClient />\` component
|
|
5281
5306
|
|
|
5282
|
-
|
|
5307
|
+
[//]: # 'ClientEntryFileExample'
|
|
5283
5308
|
|
|
5284
5309
|
\`\`\`tsx
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
Resolved loader data fetched by routes is automatically dehydrated and rehydrated by TanStack Router so long as you complete the standard SSR steps outlined in this guide.
|
|
5291
|
-
|
|
5292
|
-
⚠️ If you are using deferred data streaming, you will also need to ensure that you have implemented the [SSR Streaming & Stream Transform](#streaming-ssr) pattern near the end of this guide.
|
|
5293
|
-
|
|
5294
|
-
For more information on how to utilize data loading, see the [Data Loading](../data-loading.md) guide.
|
|
5310
|
+
// src/entry-client.tsx
|
|
5311
|
+
import { hydrateRoot } from 'react-dom/client'
|
|
5312
|
+
import { RouterClient } from '@tanstack/react-router/ssr/client'
|
|
5313
|
+
import { createRouter } from './router'
|
|
5295
5314
|
|
|
5296
|
-
|
|
5315
|
+
const router = createRouter()
|
|
5297
5316
|
|
|
5298
|
-
|
|
5317
|
+
hydrateRoot(document, <RouterClient router={router} />)
|
|
5318
|
+
\`\`\`
|
|
5299
5319
|
|
|
5300
|
-
|
|
5301
|
-
// src/entry-server.tsx
|
|
5320
|
+
[//]: # 'ClientEntryFileExample'
|
|
5302
5321
|
|
|
5303
|
-
|
|
5304
|
-
\`\`\`
|
|
5322
|
+
With this setup, your application will be rendered on the server and then hydrated on the client!
|
|
5305
5323
|
|
|
5306
|
-
|
|
5324
|
+
## Streaming SSR
|
|
5307
5325
|
|
|
5308
|
-
|
|
5326
|
+
Streaming SSR is the most modern flavor of SSR and is the process of continuously and incrementally sending HTML markup to the client as it is rendered on the server. This is slightly different from traditional SSR in concept because beyond being able to dehydrate and rehydrate a critical first paint, markup and data with less priority or slower response times can be streamed to the client after the initial render, but in the same request.
|
|
5309
5327
|
|
|
5310
|
-
|
|
5311
|
-
// src/entry-server.tsx
|
|
5312
|
-
if (router.hasNotFoundMatch()) statusCode = 404
|
|
5313
|
-
\`\`\`
|
|
5328
|
+
This pattern can be useful for pages that have slow or high-latency data fetching requirements. For example, if you have a page that needs to fetch data from a third-party API, you can stream the critical initial markup and data to the client and then stream the less-critical third-party data to the client as it is resolved.
|
|
5314
5329
|
|
|
5315
|
-
|
|
5330
|
+
> [!NOTE]
|
|
5331
|
+
> This streaming pattern is all automatic as long as you are using either \`defaultStreamHandler\` or \`renderRouterToStream\`.
|
|
5316
5332
|
|
|
5317
|
-
|
|
5333
|
+
using \`defaultStreamHandler\`
|
|
5318
5334
|
|
|
5319
5335
|
\`\`\`tsx
|
|
5320
5336
|
// src/entry-server.tsx
|
|
5321
|
-
import
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5337
|
+
import {
|
|
5338
|
+
createRequestHandler,
|
|
5339
|
+
defaultStreamHandler,
|
|
5340
|
+
} from '@tanstack/react-router/ssr/server'
|
|
5325
5341
|
import { createRouter } from './router'
|
|
5326
5342
|
|
|
5327
|
-
export async function render(
|
|
5328
|
-
const
|
|
5329
|
-
|
|
5330
|
-
const memoryHistory = createMemoryHistory({
|
|
5331
|
-
initialEntries: [url],
|
|
5332
|
-
})
|
|
5333
|
-
|
|
5334
|
-
router.update({
|
|
5335
|
-
history: memoryHistory,
|
|
5336
|
-
})
|
|
5337
|
-
|
|
5338
|
-
await router.load()
|
|
5339
|
-
|
|
5340
|
-
const appHtml = ReactDOMServer.renderToString(<StartServer router={router} />)
|
|
5343
|
+
export async function render({ request }: { request: Request }) {
|
|
5344
|
+
const handler = createRequestHandler({ request, createRouter })
|
|
5341
5345
|
|
|
5342
|
-
|
|
5343
|
-
response.setHeader('Content-Type', 'text/html')
|
|
5344
|
-
response.end(\`<!DOCTYPE html>\${appHtml}\`)
|
|
5346
|
+
return await handler(defaultStreamHandler)
|
|
5345
5347
|
}
|
|
5346
5348
|
\`\`\`
|
|
5347
5349
|
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
On the client, things are much simpler.
|
|
5351
|
-
|
|
5352
|
-
- Create your router instance
|
|
5353
|
-
- Render your application using the \`<StartClient />\` component
|
|
5350
|
+
using \`renderRouterToStream\`
|
|
5354
5351
|
|
|
5355
5352
|
\`\`\`tsx
|
|
5356
|
-
// src/entry-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5353
|
+
// src/entry-server.tsx
|
|
5354
|
+
import {
|
|
5355
|
+
createRequestHandler,
|
|
5356
|
+
renderRouterToStream,
|
|
5357
|
+
RouterServer,
|
|
5358
|
+
} from '@tanstack/react-router/ssr/server'
|
|
5362
5359
|
import { createRouter } from './router'
|
|
5363
5360
|
|
|
5364
|
-
|
|
5361
|
+
export function render({ request }: { request: Request }) {
|
|
5362
|
+
const handler = createRequestHandler({ request, createRouter })
|
|
5365
5363
|
|
|
5366
|
-
|
|
5364
|
+
return handler(({ request, responseHeaders, router }) =>
|
|
5365
|
+
renderRouterToStream({
|
|
5366
|
+
request,
|
|
5367
|
+
responseHeaders,
|
|
5368
|
+
router,
|
|
5369
|
+
children: <RouterServer router={router} />,
|
|
5370
|
+
}),
|
|
5371
|
+
)
|
|
5372
|
+
}
|
|
5367
5373
|
\`\`\`
|
|
5368
5374
|
|
|
5369
|
-
With this setup, your application will be rendered on the server and then hydrated on the client!
|
|
5370
|
-
|
|
5371
|
-
## Streaming SSR
|
|
5372
|
-
|
|
5373
|
-
Streaming SSR is the most modern flavor of SSR and is the process of continuously and incrementally sending HTML markup to the client as it is rendered on the server. This is slightly different from traditional SSR in concept because beyond being able to dehydrate and rehydrate a critical first paint, markup and data with less priority or slower response times can be streamed to the client after the initial render, but in the same request.
|
|
5374
|
-
|
|
5375
|
-
This pattern can be useful for pages that have slow or high-latency data fetching requirements. For example, if you have a page that needs to fetch data from a third-party API, you can stream the critical initial markup and data to the client and then stream the less-critical third-party data to the client as it is resolved.
|
|
5376
|
-
|
|
5377
|
-
**This streaming pattern is all automatic as long as you are using \`renderToPipeableStream\`**.
|
|
5378
|
-
|
|
5379
5375
|
## Streaming Dehydration/Hydration
|
|
5380
5376
|
|
|
5381
5377
|
Streaming dehydration/hydration is an advanced pattern that goes beyond markup and allows you to dehydrate and stream any supporting data from the server to the client and rehydrate it on arrival. This is useful for applications that may need to further use/manage the underlying data that was used to render the initial markup on the server.
|
|
@@ -5395,22 +5391,6 @@ If you feel that there are other types that should be supported by default, plea
|
|
|
5395
5391
|
|
|
5396
5392
|
If you are using more complex data types like \`Map\`, \`Set\`, \`BigInt\`, etc, you may need to use a custom serializer to ensure that your type-definitions are accurate and your data is correctly serialized and deserialized. We are currently working on both a more robust serializer and a way to customize the serializer for your application. Open an issue if you are interested in helping out!
|
|
5397
5393
|
|
|
5398
|
-
<!-- This is where the \`serializer\` option on \`createRouter\` comes in. -->
|
|
5399
|
-
|
|
5400
|
-
The Data Serialization API allows the usage of a custom serializer that can allow us to transparently use these data types when communicating across the network.
|
|
5401
|
-
|
|
5402
|
-
<!-- The following example shows usage with [SuperJSON](https://github.com/blitz-js/superjson), however, anything that implements [\`Start Serializer\`](../../api/router/RouterOptionsType.md#serializer-property) can be used. -->
|
|
5403
|
-
|
|
5404
|
-
\`\`\`tsx
|
|
5405
|
-
import { SuperJSON } from 'superjson'
|
|
5406
|
-
|
|
5407
|
-
const router = createRouter({
|
|
5408
|
-
serializer: SuperJSON,
|
|
5409
|
-
})
|
|
5410
|
-
\`\`\`
|
|
5411
|
-
|
|
5412
|
-
Just like that, TanStack Router will now appropriately use SuperJSON to serialize data across the network.
|
|
5413
|
-
|
|
5414
5394
|
# Static Route Data
|
|
5415
5395
|
|
|
5416
5396
|
When creating routes, you can optionally specify a \`staticData\` property in the route's options. This object can literally contain anything you want as long as it's synchronously available when you create your route.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-router",
|
|
3
|
-
"version": "1.121.
|
|
3
|
+
"version": "1.121.41",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"tiny-invariant": "^1.3.3",
|
|
81
81
|
"tiny-warning": "^1.0.3",
|
|
82
82
|
"isbot": "^5.1.22",
|
|
83
|
-
"@tanstack/
|
|
84
|
-
"@tanstack/
|
|
83
|
+
"@tanstack/router-core": "1.121.40",
|
|
84
|
+
"@tanstack/history": "1.121.34"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@testing-library/jest-dom": "^6.6.3",
|