Skip to content

Commit 713d1a4

Browse files
authored
Merge branch 'main' into blog/how-we-test-tanstack-ai-across-7-providers
2 parents 1b9bcb6 + c2c0e96 commit 713d1a4

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

src/blog/react-server-components.md

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ Here is an RSC in TanStack Start:
6363
6464
```tsx
6565
import { createServerFn } from '@tanstack/react-start'
66-
import { renderToReadableStream } from '@tanstack/react-start/rsc'
66+
import {
67+
createFromReadableStream,
68+
renderToReadableStream,
69+
} from '@tanstack/react-start/rsc'
6770

6871
// Create a server function
6972
const getGreeting = createServerFn().handler(async () => {
@@ -119,6 +122,12 @@ Let me explain.
119122
TanStack Query illustrates this so well. It does not need a special "RSC mode". Once the RSC payload is part of an async query, you still get explicit cache keys, `staleTime`, background refetching, and the rest of Query's toolbox. For static content, just set `staleTime: Infinity` and you are done.
120123

121124
```tsx
125+
import { createServerFn } from '@tanstack/react-start'
126+
import {
127+
createFromReadableStream,
128+
renderToReadableStream,
129+
} from '@tanstack/react-start/rsc'
130+
122131
const getGreeting = createServerFn().handler(async () => {
123132
return renderToReadableStream(<h1>Hello from the server</h1>)
124133
})
@@ -160,6 +169,30 @@ export const Route = createFileRoute('/hello')({
160169

161170
> Navigate from `/posts/abc` to `/posts/xyz` and the loader runs again. Navigate back to `/posts/abc` and Router can serve the cached result instantly. That snappy back-button experience falls out of the same loader caching model you are already using.
162171
172+
### CDN: Cache The GET Response Itself
173+
174+
Because GET server functions are still just HTTP under the hood, you can also cache the response itself at the CDN layer.
175+
176+
```tsx
177+
import { createServerFn } from '@tanstack/react-start'
178+
import { renderToReadableStream } from '@tanstack/react-start/rsc'
179+
import { setResponseHeaders } from '@tanstack/react-start/server'
180+
181+
const getGreeting = createServerFn({ method: 'GET' }).handler(async () => {
182+
setResponseHeaders(
183+
new Headers({
184+
'Cache-Control': 'public, max-age=0, must-revalidate',
185+
'Netlify-CDN-Cache-Control':
186+
'public, max-age=300, durable, stale-while-revalidate=300',
187+
}),
188+
)
189+
190+
return renderToReadableStream(<h1>Hello from the server</h1>)
191+
})
192+
```
193+
194+
That is the same pattern we use here for blog and docs content. Browser cache rules can stay conservative while the CDN caches the server function response much more aggressively.
195+
163196
With Start, RSCs fit into the same data workflows you already use.
164197

165198
## Security: One-Way Data Flow
@@ -224,17 +257,19 @@ That is the tradeoff:
224257

225258
That is why we think they matter. Not because every route should become a server component. Because when you use them where they fit, the payoff is measurable and not subtle.
226259

227-
## Introducing Composite Components, the anti-`'use client'`
260+
## Introducing Composite Components
228261

229262
Everything above stands on its own. If all TanStack Start did was treat RSCs as fetchable, cacheable, renderable data, we would already think that was a better foundation for RSCs.
230263

231264
But we kept pulling on one question: what if the server did not need to decide every client-shaped part of the UI at all?
232265

233266
That led us to create something entirely new: **Composite Components**.
234267

235-
`use client` still matters when the server intentionally wants to render a client component. Composite Components are for the opposite case. The server can leave join points for client UI without needing to know what goes there.
268+
`use client` still works the same way in TanStack Start when the server intentionally wants to render a client component. `use server` does not. Start uses explicit [Server Functions](/start/latest/docs/framework/react/guide/server-functions) instead.
269+
270+
Composite Components are not a replacement for `use client`. They solve a similar composition problem from the opposite direction. Instead of the server deciding which client component renders where, the server can leave join points open and let the client own the tree and decide what fills them.
236271

237-
That is the part that feels genuinely new to us. Most RSC systems let the server decide where client components render. Composite Components let the server leave that decision open.
272+
That is the part that feels genuinely new to us.
238273

239274
### Slots Inside One Component
240275

src/routes/__root.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ function ShellComponent({ children }: { children: React.ReactNode }) {
185185
}, [isNavigating])
186186

187187
const canonicalPath = useRouterState({
188-
select: (s) => s.resolvedLocation?.pathname || '/',
188+
select: (s) => s.location?.pathname || '/',
189189
})
190190

191191
const preferredCanonicalPath = getCanonicalPath(canonicalPath)

0 commit comments

Comments
 (0)