feat(tanstack): /_serverFn CDN caching arrives with a version bump (opt-out) - #523
Merged
Conversation
Shipping the previous PR left the feature needing two edits in every site — a
`src/start.ts` and a `cdnCacheControl` option. That is the same per-site
boilerplate the package split exists to remove: twenty sites, twenty PRs, and
any site that skips one silently gets nothing.
Two changes make it opt-OUT instead.
## The default flips to "serverfn-segment"
Safe because the mode is inert until a verified marker arrives: a client that
never sends `__cseg` keeps getting `no-store`, so enabling it cannot change
behaviour on its own. Three tests pin that claim rather than leaving it in a
comment — no marker (HTML and `/_serverFn`) stays `no-store`, a valid marker
engages with no site config, and `cdnCacheControl: "no-store"` still opts out.
## The vite plugin supplies a default Start entry
`#tanstack-start-entry` is a subpath import of `@tanstack/start-client-core`.
With no `src/start.ts` it resolves to a fake entry exporting
`startInstance = undefined`, so the site gets no `serverFns.fetch` hook — and
that hook is what appends the marker. Without it the worker-side default above
would never see a marker and the feature could not engage.
`decoVitePlugin` now aliases that specifier to `sdk/startEntry` when the site
has no start file of its own. Strictly conditional on absence: a site that owns
its `src/start.ts` keeps it, since ours would otherwise silently replace
whatever else it configures there.
## Verified end to end, not just by unit test
Built a real site with the site-level config REMOVED (no `src/start.ts`, no
`cdnCacheControl`), ran it under `wrangler dev`, and drove SPA navigation with
Chrome:
GET /_serverFn/… __cseg=desktop.<build> → CDN-Cache-Control: public, max-age=1800
and fail-closed intact on the same build: no marker, wrong device, bot UA and
login cookie all still `no-store`, HTML documents still `no-store`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
🎉 This PR is included in version 7.57.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #513. That PR shipped the feature but left it needing two edits in every site — a
src/start.tsand acdnCacheControloption. That's the same per-site boilerplate the package split existsto remove: twenty sites, twenty PRs, and any site that skips one silently gets nothing.
This makes it opt-out: a site picks the feature up from a version bump, and only touches config to turn it
off.
1. The default flips to
"serverfn-segment"Safe because the mode is inert until a verified marker arrives. A client that never sends
__csegkeepsgetting
no-store, so flipping the default cannot change behaviour on its own.Three tests pin that claim instead of leaving it in a comment:
/_serverFn) → staysno-storecdnCacheControl: "no-store"→ still opts out2. The vite plugin supplies a default Start entry
This is the part that actually unlocks "just bump".
#tanstack-start-entryis a subpath import of@tanstack/start-client-core. With nosrc/start.tsitresolves to a fake entry exporting
startInstance = undefined, so the site gets noserverFns.fetchhook— and that hook is what appends the marker to the URL. Without it, the worker-side default above would never
see a marker and the feature could never engage.
decoVitePluginnow aliases that specifier tosdk/startEntrywhen the site has no start file of its own.Strictly conditional on absence. A site that owns its
src/start.tskeeps it — ours would otherwisesilently replace whatever else it configures there. Such a site opts in by composing
decoServerFnFetchitself, exactly as before.
Verified end to end, not just by unit test
Took a real site, removed the site-level config (
src/start.tsdeleted,cdnCacheControlremoved), builtit, ran it under
wrangler dev, and drove SPA navigation with Chrome:Fail-closed intact on that same zero-config build:
public, max-age=1800✅no-storeno-storeno-storeno-storeno-store2590tests passing,+3new. Typecheck clean across the three packages.What this means for the sites
Sites with a pending version bump (montecarlo #202, zeedog #168 and others) get CDN caching of SPA navigation
and prefetch with no further change.
buildSegmentis still required for the marker to verify — sites withoutone keep
no-storeand get the boot warning added in #512.HTML is still
no-store, and still needs separate work.🤖 Generated with Claude Code
Summary by cubic
Makes CDN caching of
/_serverFnarrive with a version bump instead of a per-site PR. ThecdnCacheControldefault flips from"no-store"to"serverfn-segment", anddecoVitePluginnow supplies a default Start entry when the site has nosrc/start.tsof its own.__csegmarker arrives, so clients without one still getno-store.decoServerFnFetch, the hook that appends the marker to/_serverFnURLs.src/start.tskeep it; an explicitcdnCacheControl: "no-store"still opts out.no-store.Written for commit 5d7cf60. Summary will update on new commits.