@bgub/fig-tanstack-start 0.0.0-tegami-trusted-publish-setup → 0.1.0-alpha.2
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/CHANGELOG.md +225 -0
- package/LICENSE +21 -0
- package/README.md +280 -3
- package/dist/client-B2okTbp3.js +29 -0
- package/dist/client-B2okTbp3.js.map +1 -0
- package/dist/client.d.ts +13 -0
- package/dist/client.js +2 -0
- package/dist/data.d.ts +14 -0
- package/dist/data.js +34 -0
- package/dist/data.js.map +1 -0
- package/dist/default-entry/client.d.ts +1 -0
- package/dist/default-entry/client.js +7 -0
- package/dist/default-entry/client.js.map +1 -0
- package/dist/default-entry/server.d.ts +4 -0
- package/dist/default-entry/server.js +6 -0
- package/dist/default-entry/server.js.map +1 -0
- package/dist/default-entry/start.d.ts +4 -0
- package/dist/default-entry/start.js +6 -0
- package/dist/default-entry/start.js.map +1 -0
- package/dist/payload-assets-eHfSAMbN.js +14 -0
- package/dist/payload-assets-eHfSAMbN.js.map +1 -0
- package/dist/payload-internal-CZhfVhwH.js +168 -0
- package/dist/payload-internal-CZhfVhwH.js.map +1 -0
- package/dist/payload.d.ts +19 -0
- package/dist/payload.js +38 -0
- package/dist/payload.js.map +1 -0
- package/dist/plugin/vite.d.ts +6 -0
- package/dist/plugin/vite.js +857 -0
- package/dist/plugin/vite.js.map +1 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.js +111 -0
- package/dist/server.js.map +1 -0
- package/dist/start-context-DZ2gsb5m.js +12 -0
- package/dist/start-context-DZ2gsb5m.js.map +1 -0
- package/dist/storage-context.d.ts +9 -0
- package/dist/storage-context.js +21 -0
- package/dist/storage-context.js.map +1 -0
- package/dist/store-CibAGqiI.js +13 -0
- package/dist/store-CibAGqiI.js.map +1 -0
- package/dist/transport-DKcSG44e.js +33 -0
- package/dist/transport-DKcSG44e.js.map +1 -0
- package/package.json +90 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
## @bgub/fig-tanstack-start@0.1.0-alpha.1
|
|
2
|
+
|
|
3
|
+
### Refresh resolves the app's renderer runtime
|
|
4
|
+
|
|
5
|
+
`figRefresh` now imports `@bgub/fig-dom/refresh` through its bare specifier
|
|
6
|
+
rather than a resolved `/@fs/` path, so app-level aliases, dedupe, and
|
|
7
|
+
prebundling apply and the refresh scheduler cannot be instantiated twice.
|
|
8
|
+
|
|
9
|
+
### TanStack Start's client graph is prebundled
|
|
10
|
+
|
|
11
|
+
The TanStack Start adapter now prebundles `@tanstack/start-client-core` in
|
|
12
|
+
development while leaving its application-bound router and Start imports as
|
|
13
|
+
external Vite modules. This reduces the module-request waterfall without
|
|
14
|
+
freezing generated app entries or the linked Fig adapter packages. Production
|
|
15
|
+
continues to use Vite's normal application bundling.
|
|
16
|
+
|
|
17
|
+
### Make Payload trees directly renderable
|
|
18
|
+
|
|
19
|
+
`createPayloadComponent` now creates a props-typed component backed by Fig's
|
|
20
|
+
ordinary data store. Complete props form its cache identity by default through
|
|
21
|
+
a canonical encoding of Payload-compatible values, and the component works
|
|
22
|
+
with route loaders and the existing data-resource freshness APIs and explicit
|
|
23
|
+
store handles.
|
|
24
|
+
|
|
25
|
+
The lower-level `payloadDataLoader` and `PayloadDataLoaderOptions` exports have
|
|
26
|
+
been removed. Use `createPayloadComponent`, or `decodePayloadStream` when
|
|
27
|
+
managing the transport and data integration directly.
|
|
28
|
+
|
|
29
|
+
TanStack Start replaces `payloadResource({ key, render })` with
|
|
30
|
+
`createPayloadComponent({ key, load: serverPayload(render) })`. Its compiler
|
|
31
|
+
can extract a component imported from `.server.tsx`, while initial companion
|
|
32
|
+
streams, client references, and compiled asset dependencies keep their existing
|
|
33
|
+
transport behavior.
|
|
34
|
+
|
|
35
|
+
Payload component loaders receive the resolved resource `key` alongside
|
|
36
|
+
`signal`, so framework transports can register responses under the exact cache
|
|
37
|
+
entry without changing ordinary data loaders.
|
|
38
|
+
|
|
39
|
+
Default keys are canonical across plain-object property order, and Payload
|
|
40
|
+
components use their namespace as their DevTools label. TanStack Start renders
|
|
41
|
+
the supplied component inside the Payload renderer so root-level reads and
|
|
42
|
+
suspension work, and rejects uncompiled `serverPayload` calls before invoking
|
|
43
|
+
application code.
|
|
44
|
+
|
|
45
|
+
Payload rendering also rejects nesting one Payload component inside another in
|
|
46
|
+
development. Payload components are client-visible delivery boundaries;
|
|
47
|
+
compose ordinary server components inside them or mount separate Payload
|
|
48
|
+
components from the client tree to preserve independent refresh keys.
|
|
49
|
+
|
|
50
|
+
### Promise-valued children render through Suspense
|
|
51
|
+
|
|
52
|
+
`FigNode` now accepts promises of nodes. Promise children occupy distinct,
|
|
53
|
+
host-transparent child slots, suspend through the nearest `Suspense`, and route
|
|
54
|
+
rejections or invalid resolved children through normal error handling.
|
|
55
|
+
|
|
56
|
+
HTML rendering retains exact promise children as independent streaming tasks,
|
|
57
|
+
while Payload uses node-validated promise rows that decode to the same child
|
|
58
|
+
shape. Payload-rendered async components are invoked once and retain their
|
|
59
|
+
component-scoped assets on the outlined row.
|
|
60
|
+
|
|
61
|
+
### Move HTML escaping helpers to a focused subpath
|
|
62
|
+
|
|
63
|
+
`escapeAttribute`, `escapeText`, `escapeScriptText`, and `escapeScriptJson` now export from
|
|
64
|
+
`@bgub/fig-server/html` instead of the main `@bgub/fig-server` entry.
|
|
65
|
+
The dedicated subpath keeps companion-markup helpers separate from server
|
|
66
|
+
render entry points while preserving their exact escaping behavior. The
|
|
67
|
+
TanStack Start adapter now consumes these helpers, Fig's internal data-store
|
|
68
|
+
brand predicate, and its own storage-context API instead of duplicating them.
|
|
69
|
+
|
|
70
|
+
### Expose render-discovered assets as response preload headers
|
|
71
|
+
|
|
72
|
+
Server stream results now provide a bounded, deduplicated HTTP `Link` value for
|
|
73
|
+
preconnects, fonts, stylesheets, explicit preloads, and module preloads
|
|
74
|
+
discovered before the shell becomes ready. Filters let adapters exclude asset
|
|
75
|
+
URLs that are unsafe for a shared cache.
|
|
76
|
+
|
|
77
|
+
The TanStack Start renderer can opt into merging that shell snapshot with the
|
|
78
|
+
response's existing `Link` header before constructing the streamed response.
|
|
79
|
+
Assets discovered after the shell continue to arrive through HTML streaming.
|
|
80
|
+
|
|
81
|
+
### Build generated TanStack Start file routes with Fig
|
|
82
|
+
|
|
83
|
+
`@bgub/fig-tanstack-router` now implements generated file routes, lazy route
|
|
84
|
+
records, lazy components, and lazy loader functions. TanStack Start builds and
|
|
85
|
+
reloads those routes in development through its existing generator and code
|
|
86
|
+
splitter.
|
|
87
|
+
|
|
88
|
+
`@bgub/fig-tanstack-start` now exposes Start configuration and middleware
|
|
89
|
+
factories. Its demo covers request-isolated middleware context, server and
|
|
90
|
+
client redirects, generated error and not-found routes, split chunks, SSR,
|
|
91
|
+
hydration, and server-function mutations.
|
|
92
|
+
|
|
93
|
+
### Complete Fig-native data and navigation patterns
|
|
94
|
+
|
|
95
|
+
TanStack Start routes can now preload Payload data and return immediately,
|
|
96
|
+
letting Fig Suspense stream the result and its asset resources without copying
|
|
97
|
+
values into Router loader data. Initial Payload responses registered after the
|
|
98
|
+
document shell starts are embedded before hydration, preventing a duplicate
|
|
99
|
+
client request.
|
|
100
|
+
|
|
101
|
+
The Router adapter adds modern object-only `useBlocker` and reactive
|
|
102
|
+
`useCanGoBack` hooks, makes the concrete Router and RouteApi constructors
|
|
103
|
+
internal, and rejects unsupported proximity preloading in `LinkProps`.
|
|
104
|
+
Fig's structural `ViewTransition` remains the sole document-transition owner,
|
|
105
|
+
even when a TanStack navigation carries its `viewTransition` option.
|
|
106
|
+
|
|
107
|
+
### Give each matched route ownership of its Fig assets
|
|
108
|
+
|
|
109
|
+
Route stylesheets, preload hints, preconnects, font preloads, and async scripts
|
|
110
|
+
now enter Fig's shared asset registry at the matched subtree. This gives Start
|
|
111
|
+
streaming, client navigation, and Payload assets one deduplicating ownership
|
|
112
|
+
model while title, meta, inline styles, JSON-LD, and synchronous scripts retain
|
|
113
|
+
their declared document positions.
|
|
114
|
+
|
|
115
|
+
Manifest `assetCrossOrigin` configuration now belongs to `createRouter`
|
|
116
|
+
options, where it is available before the root match renders.
|
|
117
|
+
|
|
118
|
+
### Fix first-load styling and development client navigation
|
|
119
|
+
|
|
120
|
+
Keep TanStack Start's compiler-sensitive client modules out of Vite dependency
|
|
121
|
+
prebundling so client navigation uses the client server-function transport
|
|
122
|
+
instead of executing server-only context access in the browser. Preserve
|
|
123
|
+
browser-extension roots appended to document singletons during hydration so a
|
|
124
|
+
third-party node cannot trigger document replacement and remove stylesheets.
|
|
125
|
+
|
|
126
|
+
### Compile Payload components and their assets
|
|
127
|
+
|
|
128
|
+
Fig TanStack Start now turns stylesheet imports in the ordinary component graph
|
|
129
|
+
reached from a `payloadResource` render callback into Payload asset dependencies
|
|
130
|
+
automatically. The same declaration compiles to a private TanStack server
|
|
131
|
+
function and Payload response, so applications no longer author
|
|
132
|
+
`createServerFn`, `renderPayloadResponse`, or request plumbing for Payload
|
|
133
|
+
routes. Payload rendering is independent of filenames. Applications
|
|
134
|
+
conventionally use `.payload.tsx` for the shared resource declaration, but the
|
|
135
|
+
suffix is only a human label. Components and assets referenced only by the
|
|
136
|
+
render callback are omitted from the browser bundle. Compiled styles use the
|
|
137
|
+
existing Payload row ownership, dedupe, streaming, and reveal-gating behavior
|
|
138
|
+
without requiring an `assets(stylesheet(...))` wrapper.
|
|
139
|
+
|
|
140
|
+
Applications mark the exceptional SSR-plus-hydration boundary with
|
|
141
|
+
`<Isomorphic component={Counter} ... />` and an ordinary static import. The
|
|
142
|
+
generated per-bundle manifest owns module resolution, stable component
|
|
143
|
+
identity, and client CSS metadata, so applications no longer author
|
|
144
|
+
`clientReference`, `createPayloadClientReferenceResolver`, ids, or dynamic
|
|
145
|
+
imports. Ordinary component uses remain Payload-rendered.
|
|
146
|
+
|
|
147
|
+
### Own the TanStack Start document transport
|
|
148
|
+
|
|
149
|
+
`StartScripts` now owns Fig data serialization, the initial Payload insertion
|
|
150
|
+
point, and TanStack's bootstrap scripts as one ordered document surface. The
|
|
151
|
+
Payload transport targets a Fig-owned marker instead of matching TanStack's
|
|
152
|
+
private hydration-barrier markup.
|
|
153
|
+
|
|
154
|
+
The Vite adapter records its exact Router and Start core compatibility profile
|
|
155
|
+
and rejects emitted Solid Router or Start adapter modules. Server-only assets
|
|
156
|
+
are still mirrored into the public client output, but a conflicting client
|
|
157
|
+
asset now fails the build instead of being silently overwritten.
|
|
158
|
+
|
|
159
|
+
### TanStack Start gains state-preserving Fast Refresh
|
|
160
|
+
|
|
161
|
+
The TanStack Start Vite adapter now installs Fig Fast Refresh automatically.
|
|
162
|
+
Component edits update in place and preserve hook state in accepted modules.
|
|
163
|
+
|
|
164
|
+
`@bgub/fig-vite` is now a public package containing the reusable Fast Refresh
|
|
165
|
+
and server data-resource transforms.
|
|
166
|
+
|
|
167
|
+
### Add Payload routes to the TanStack Start adapter
|
|
168
|
+
|
|
169
|
+
`@bgub/fig-tanstack-start/payload` now exposes `payloadResource`, which compiles
|
|
170
|
+
an inline render callback into a private server function and Fig-owned route
|
|
171
|
+
data resource. Applications supply the cache key and component tree without
|
|
172
|
+
authoring transport plumbing. The shared declaration can stay in one
|
|
173
|
+
`.payload.tsx` module; its render callback and render-only imports are omitted
|
|
174
|
+
from the browser build. The initial SSR response is embedded into the document
|
|
175
|
+
and adopted without refetching; client navigation and refresh use the same
|
|
176
|
+
resource request path. Payload data rows
|
|
177
|
+
hydrate the shared store, asset resources are retained on their owning server
|
|
178
|
+
segments or inserted through the browser registry, and client references retain
|
|
179
|
+
their resolver-defined identity. `decodePayloadStream` and `payloadDataLoader`
|
|
180
|
+
now expose `retainAssets` for server document renderers that need this delivery
|
|
181
|
+
path.
|
|
182
|
+
|
|
183
|
+
`@bgub/fig-tanstack-start/server` exposes the lower-level
|
|
184
|
+
`renderPayloadResponse` used by the generated TanStack server function; it
|
|
185
|
+
defaults its render abort signal to the incoming request, so a disconnected
|
|
186
|
+
client cancels the Payload render. Shell
|
|
187
|
+
HTML streams while outlined Suspense holes settle, and the completed initial
|
|
188
|
+
responses are embedded before TanStack starts full-document hydration. The Vite
|
|
189
|
+
adapter also publishes assets imported only by server modules into the client
|
|
190
|
+
build output. Fig Router links also consume TanStack's `viewTransition`
|
|
191
|
+
navigation option without forwarding it as an invalid attribute to the rendered
|
|
192
|
+
anchor, and derive active state from the resolved route instead of an in-flight
|
|
193
|
+
location.
|
|
194
|
+
|
|
195
|
+
### Add the TanStack Start runtime adapter
|
|
196
|
+
|
|
197
|
+
`createDataStore` now creates a root-neutral Fig store that route loaders can
|
|
198
|
+
populate before a renderer exists. Server and client renderers adopt that exact
|
|
199
|
+
store, preserving one cache while attaching their lifecycle and scheduling.
|
|
200
|
+
|
|
201
|
+
The new TanStack Start runtime uses the store for route loading, server
|
|
202
|
+
rendering, Fig-owned document serialization, client deserialization, and
|
|
203
|
+
hydration. Route-managed head and script output maps through the Router adapter,
|
|
204
|
+
including Fig asset resources. The end-to-end contract verifies no initial
|
|
205
|
+
client refetch and exactly one reload after invalidation.
|
|
206
|
+
|
|
207
|
+
### Build Fig applications with TanStack Start and Vite
|
|
208
|
+
|
|
209
|
+
`@bgub/fig-tanstack-start/plugin/vite` now delegates client and SSR builds,
|
|
210
|
+
development and preview serving, manifests, and server-function compilation to
|
|
211
|
+
TanStack Start's plugin core. Default entries stream and hydrate Fig documents
|
|
212
|
+
without application-owned build or HTTP glue.
|
|
213
|
+
|
|
214
|
+
The package root now exposes `createServerFn`. Compiled mutations use TanStack's
|
|
215
|
+
RPC transport and can invalidate the live Fig data store afterward; the demo
|
|
216
|
+
proves the full production flow from SSR hydration through mutation and one
|
|
217
|
+
data-resource refresh.
|
|
218
|
+
|
|
219
|
+
## @bgub/fig-tanstack-start@0.1.0-alpha.0 (alpha)
|
|
220
|
+
|
|
221
|
+
### Initial alpha release
|
|
222
|
+
|
|
223
|
+
First public alpha release of the TanStack Start adapter for Fig.
|
|
224
|
+
|
|
225
|
+
# Changelog
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Ben Gubler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,5 +1,282 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @bgub/fig-tanstack-start
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The TanStack Start adapter for Fig. TanStack owns builds, requests, route
|
|
4
|
+
loading, redirects, and server-function transport; Fig owns rendering, data
|
|
5
|
+
resources, asset resources, and the single data store used by loaders and
|
|
6
|
+
components.
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
```bash
|
|
9
|
+
pnpm add @bgub/fig-tanstack-start @bgub/fig-tanstack-router
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Add the adapter to Vite:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { tanstackStart } from "@bgub/fig-tanstack-start/plugin/vite";
|
|
16
|
+
|
|
17
|
+
const plugins = [tanstackStart()];
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The plugin supplies the default client and server entries, including streamed
|
|
21
|
+
Fig SSR, full-document hydration, and state-preserving Fig Fast Refresh. It
|
|
22
|
+
currently uses TanStack's Solid target
|
|
23
|
+
as a private compiler compatibility layer because plugin core has no custom
|
|
24
|
+
framework target. The generator currently normalizes file-route constructor
|
|
25
|
+
imports to its Solid package ID; the plugin maps that ID directly to Fig, and no
|
|
26
|
+
Solid Router or Start adapter runtime is installed or bundled. TypeScript needs the corresponding
|
|
27
|
+
compiler-only `paths` entry:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"compilerOptions": {
|
|
32
|
+
"paths": {
|
|
33
|
+
"@tanstack/solid-router": ["./node_modules/@bgub/fig-tanstack-router"],
|
|
34
|
+
"@tanstack/solid-start": ["./node_modules/@bgub/fig-tanstack-start"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Response preload headers
|
|
41
|
+
|
|
42
|
+
The default server entry leaves response `Link` headers disabled because a CDN
|
|
43
|
+
may cache and replay request-specific asset URLs. A custom server entry can opt
|
|
44
|
+
in globally or provide a resource filter:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { createFigStartHandler } from "@bgub/fig-tanstack-start/server";
|
|
48
|
+
|
|
49
|
+
const fetch = createFigStartHandler({
|
|
50
|
+
preloadHeader: {
|
|
51
|
+
filter: (resource) => resource.href.startsWith("/assets/"),
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export default { fetch };
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The header contains assets discovered before Fig's document shell becomes
|
|
59
|
+
ready. Assets discovered later through Suspense or Payload remain in the HTML
|
|
60
|
+
stream and cannot be added after the response is created.
|
|
61
|
+
|
|
62
|
+
The Start mapping lets the generated registration footer carry middleware
|
|
63
|
+
context types from a conventional `src/start.ts` into `createServerFn`.
|
|
64
|
+
|
|
65
|
+
Create the router with a root-neutral Fig store:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { createStartDataContext } from "@bgub/fig-tanstack-start";
|
|
69
|
+
import {
|
|
70
|
+
createRouter,
|
|
71
|
+
createRootRouteWithContext,
|
|
72
|
+
} from "@bgub/fig-tanstack-router";
|
|
73
|
+
|
|
74
|
+
const startData = createStartDataContext();
|
|
75
|
+
const rootRoute = createRootRouteWithContext<typeof startData.context>()({
|
|
76
|
+
component: Document,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export const router = createRouter({
|
|
80
|
+
...startData,
|
|
81
|
+
routeTree: rootRoute,
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The root document renders route-managed assets followed by Start's combined Fig data and TanStack script transport:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import { StartScripts } from "@bgub/fig-tanstack-start";
|
|
89
|
+
import { HeadContent, Outlet } from "@bgub/fig-tanstack-router";
|
|
90
|
+
|
|
91
|
+
function Document() {
|
|
92
|
+
return (
|
|
93
|
+
<html lang="en">
|
|
94
|
+
<head>
|
|
95
|
+
<HeadContent />
|
|
96
|
+
</head>
|
|
97
|
+
<body>
|
|
98
|
+
<Outlet />
|
|
99
|
+
<StartScripts />
|
|
100
|
+
</body>
|
|
101
|
+
</html>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`StartScripts` serializes the Fig store into the server document with Fig's value codec, establishes the adapter's Payload insertion point, and then renders TanStack's bootstrap scripts. Client router creation decodes the data before TanStack hydration can start route loaders; `hydrateStart` repeats that step idempotently as a fallback before `hydrateRoot` adopts the same client store. The first `readData` therefore hits the hydrated entry without re-running its loader, and `invalidateData` operates directly on the live root store.
|
|
107
|
+
|
|
108
|
+
## Request and function middleware
|
|
109
|
+
|
|
110
|
+
The package root also exports TanStack's `createStart`, `createMiddleware`, and
|
|
111
|
+
`createCsrfMiddleware`. A conventional `src/start.ts` configures global request
|
|
112
|
+
and server-function middleware:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import {
|
|
116
|
+
createCsrfMiddleware,
|
|
117
|
+
createMiddleware,
|
|
118
|
+
createStart,
|
|
119
|
+
} from "@bgub/fig-tanstack-start";
|
|
120
|
+
|
|
121
|
+
const requestContext = createMiddleware({ type: "request" }).server(
|
|
122
|
+
({ request, next }) =>
|
|
123
|
+
next({ context: { requestId: request.headers.get("x-request-id") } }),
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
export const startInstance = createStart(() => ({
|
|
127
|
+
requestMiddleware: [
|
|
128
|
+
requestContext,
|
|
129
|
+
createCsrfMiddleware({
|
|
130
|
+
filter: (context) => context.handlerType === "serverFn",
|
|
131
|
+
}),
|
|
132
|
+
],
|
|
133
|
+
}));
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Start's global async context remains request-local across interleaved SSR and
|
|
137
|
+
server-function work. Redirects thrown by generated route loaders or
|
|
138
|
+
`beforeLoad` use Router Core's normal server and client redirect handling.
|
|
139
|
+
|
|
140
|
+
## Server functions
|
|
141
|
+
|
|
142
|
+
The package root exports TanStack's `createServerFn`. The Vite plugin compiles
|
|
143
|
+
the handler into the server build and the browser call into an RPC request:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { createServerFn } from "@bgub/fig-tanstack-start";
|
|
147
|
+
|
|
148
|
+
export const renameUser = createServerFn({ method: "POST" })
|
|
149
|
+
.validator((input: { id: string; name: string }) => input)
|
|
150
|
+
.handler(async ({ data }) => {
|
|
151
|
+
await database.users.rename(data.id, data.name);
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
An async event must capture the Fig store before its first `await` when it
|
|
156
|
+
needs to refresh data afterward:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { readDataStore } from "@bgub/fig";
|
|
160
|
+
|
|
161
|
+
const data = readDataStore();
|
|
162
|
+
await renameUser({ data: { id, name }, signal });
|
|
163
|
+
data.invalidateData(userResource, id);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Payload routes
|
|
167
|
+
|
|
168
|
+
Payload routes keep Payload-rendered component trees out of the client bundle
|
|
169
|
+
while using the same Fig data store as ordinary route data. The smallest route
|
|
170
|
+
is one colocated declaration:
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
// profile.payload.tsx
|
|
174
|
+
import { createPayloadComponent } from "@bgub/fig-dom";
|
|
175
|
+
import { serverPayload } from "@bgub/fig-tanstack-start/payload";
|
|
176
|
+
import { Profile } from "./Profile.server.tsx";
|
|
177
|
+
|
|
178
|
+
export const ProfilePage = createPayloadComponent<{ id: string }>({
|
|
179
|
+
key: ["profile-payload"],
|
|
180
|
+
load: serverPayload(Profile),
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`serverPayload` accepts a component or render callback; it is the semantic
|
|
185
|
+
boundary that the compiler extracts into a private server function. It may be
|
|
186
|
+
async. The browser bundle keeps the component handle, cache, and RPC stub; it
|
|
187
|
+
omits the server render and imports used only by it. Keep the Payload component
|
|
188
|
+
declaration in a client-importable module such as `.payload.tsx` because the
|
|
189
|
+
route imports that handle. The rendered component itself may live in a
|
|
190
|
+
TanStack-protected `.server.tsx` module.
|
|
191
|
+
|
|
192
|
+
When the tree grows, the callback can import ordinary components. Those imports
|
|
193
|
+
also stay out of the browser bundle when only the callback uses them. A filename
|
|
194
|
+
does not cause a component to render through Payload—`serverPayload` does.
|
|
195
|
+
Applications do not call `createServerFn` or `renderPayloadResponse` for Payload
|
|
196
|
+
resources.
|
|
197
|
+
|
|
198
|
+
Mark the exceptional SSR-plus-hydration boundary with `Isomorphic` and an
|
|
199
|
+
ordinary static component import. For example, a separate Payload component can
|
|
200
|
+
contain the boundary:
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
import type { FigNode } from "@bgub/fig";
|
|
204
|
+
import { Isomorphic } from "@bgub/fig-tanstack-start/payload";
|
|
205
|
+
import { LikeButton } from "./LikeButton.tsx";
|
|
206
|
+
|
|
207
|
+
export function Profile({ id }: { id: string }): FigNode {
|
|
208
|
+
return <Isomorphic component={LikeButton} userId={id} />;
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The Vite plugin replaces only the `component` prop with an opaque Payload
|
|
213
|
+
reference and generates its server/browser module resolver. The component
|
|
214
|
+
remains an ordinary export and can render through Payload elsewhere without
|
|
215
|
+
the boundary. `component` must be a named or default static import.
|
|
216
|
+
Applications do not use a `.client.tsx` suffix, `clientReference`,
|
|
217
|
+
`createPayloadClientReferenceResolver`, reference ids, or dynamic imports.
|
|
218
|
+
|
|
219
|
+
The route can start the load early, then render the component normally:
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { ensureRouteData } from "@bgub/fig-tanstack-router";
|
|
223
|
+
import { createFileRoute } from "@tanstack/solid-router";
|
|
224
|
+
import { ProfilePage } from "../profile.payload.tsx";
|
|
225
|
+
|
|
226
|
+
export const Route = createFileRoute("/profiles/$id")({
|
|
227
|
+
loader: ({ context, params }) =>
|
|
228
|
+
ensureRouteData(context, ProfilePage, { id: params.id }),
|
|
229
|
+
component: ProfileRoute,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
function ProfileRoute() {
|
|
233
|
+
const { id } = Route.useParams();
|
|
234
|
+
return <ProfilePage id={id} />;
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
When the route does not need the tree before commit, preload it and return
|
|
239
|
+
`void`; Fig Suspense then owns the pending UI and stream:
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
import { Suspense } from "@bgub/fig";
|
|
243
|
+
|
|
244
|
+
export const Route = createFileRoute("/profiles/$id")({
|
|
245
|
+
loader: ({ context, params }) => {
|
|
246
|
+
context.data.preloadData(ProfilePage, { id: params.id });
|
|
247
|
+
},
|
|
248
|
+
component: () => (
|
|
249
|
+
<Suspense fallback={<p>Streaming profile…</p>}>
|
|
250
|
+
<ProfileRoute />
|
|
251
|
+
</Suspense>
|
|
252
|
+
),
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
On SSR, Fig decodes and renders the root once, retains Payload-discovered asset
|
|
257
|
+
resources on the rows that declared them, and embeds the response bytes for
|
|
258
|
+
hydration. This includes Payload resources registered after the document shell
|
|
259
|
+
starts. The document renderer emits each asset before its dependent HTML
|
|
260
|
+
segment, including streamed Suspense holes. The browser adopts the embedded
|
|
261
|
+
bytes without a second server-function call. Shell HTML streams while Suspense
|
|
262
|
+
holes settle; TanStack starts full-document hydration after each complete
|
|
263
|
+
initial Payload response is embedded in a keyed carrier. Client navigation and
|
|
264
|
+
refresh use the same raw response path.
|
|
265
|
+
|
|
266
|
+
The Vite adapter follows ordinary component imports from each `serverPayload`
|
|
267
|
+
render and compiles their static stylesheet imports into Payload asset
|
|
268
|
+
dependencies. Import CSS normally; no manual
|
|
269
|
+
`assets(stylesheet(...))` wrapper or `?url` import is needed. A Payload-rendered
|
|
270
|
+
component's stylesheet is copied from the server build into the public client
|
|
271
|
+
output. An `Isomorphic` component's hashed client CSS is attached through the
|
|
272
|
+
generated manifest. Both use the existing Payload asset row and reveal gate
|
|
273
|
+
and are emitted only when their component renders.
|
|
274
|
+
|
|
275
|
+
The [`demo-tanstack-start`](../../apps/demo-tanstack-start) app exercises the
|
|
276
|
+
adapter through Vite's production client and SSR builds: generated and split
|
|
277
|
+
file routes, streamed SSR, Router dehydration, Fig-owned data serialization,
|
|
278
|
+
full-document hydration, request-derived themes, view transitions, live
|
|
279
|
+
data-resource invalidation, nested routes, and post and asset Payload trees all
|
|
280
|
+
run through public adapter entries. The asset route embeds two independent
|
|
281
|
+
Payload resources and hydrates an explicit `Isomorphic` component whose CSS and
|
|
282
|
+
SVG are emitted through the production builds.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { n as hydrateStartDataStore } from "./transport-DKcSG44e.js";
|
|
2
|
+
import { RouterProvider } from "@bgub/fig-tanstack-router";
|
|
3
|
+
import { hydrateRoot } from "@bgub/fig-dom";
|
|
4
|
+
import { hydrateStart } from "@tanstack/start-client-core/client";
|
|
5
|
+
import { jsx } from "@bgub/fig-dom/jsx-runtime";
|
|
6
|
+
//#region src/client.tsx
|
|
7
|
+
async function hydrateStart$1(options = {}) {
|
|
8
|
+
const { container = document, ...rootOptions } = options;
|
|
9
|
+
await waitForRouterBootstrap();
|
|
10
|
+
const router = await hydrateStart();
|
|
11
|
+
const dataStore = hydrateStartDataStore(router.options.context, document);
|
|
12
|
+
const root = hydrateRoot(container, /* @__PURE__ */ jsx(RouterProvider, { router }), {
|
|
13
|
+
...rootOptions,
|
|
14
|
+
dataStore
|
|
15
|
+
});
|
|
16
|
+
window.$_TSR?.h();
|
|
17
|
+
return {
|
|
18
|
+
root,
|
|
19
|
+
router
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async function waitForRouterBootstrap() {
|
|
23
|
+
if (window.$_TSR !== void 0 || document.readyState !== "loading") return;
|
|
24
|
+
await new Promise((resolve) => document.addEventListener("DOMContentLoaded", () => resolve(), { once: true }));
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { hydrateStart$1 as t };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=client-B2okTbp3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-B2okTbp3.js","names":["hydrateStart","hydrateTanStackStart"],"sources":["../src/client.tsx"],"sourcesContent":["import {\n type Container,\n type FigRoot,\n type FigRootOptions,\n hydrateRoot,\n} from \"@bgub/fig-dom\";\nimport { RouterProvider } from \"@bgub/fig-tanstack-router\";\nimport { hydrateStart as hydrateTanStackStart } from \"@tanstack/start-client-core/client\";\nimport type { AnyRouter } from \"@tanstack/router-core\";\nimport { hydrateStartDataStore } from \"./transport.ts\";\n\nexport interface HydrateStartOptions extends Omit<\n FigRootOptions,\n \"dataPartition\" | \"dataStore\" | \"initialData\"\n> {\n container?: Container;\n}\n\nexport interface HydratedStart {\n root: FigRoot;\n router: AnyRouter;\n}\n\nexport async function hydrateStart(\n options: HydrateStartOptions = {},\n): Promise<HydratedStart> {\n const { container = document, ...rootOptions } = options;\n await waitForRouterBootstrap();\n const router = await hydrateTanStackStart();\n const dataStore = hydrateStartDataStore(router.options.context, document);\n\n const root = hydrateRoot(container, <RouterProvider router={router} />, {\n ...rootOptions,\n dataStore,\n });\n window.$_TSR?.h();\n return { root, router };\n}\n\nasync function waitForRouterBootstrap(): Promise<void> {\n if (window.$_TSR !== undefined || document.readyState !== \"loading\") return;\n await new Promise<void>((resolve) =>\n document.addEventListener(\"DOMContentLoaded\", () => resolve(), {\n once: true,\n }),\n );\n}\n"],"mappings":";;;;;;AAuBA,eAAsBA,eACpB,UAA+B,CAAC,GACR;CACxB,MAAM,EAAE,YAAY,UAAU,GAAG,gBAAgB;CACjD,MAAM,uBAAuB;CAC7B,MAAM,SAAS,MAAMC,aAAqB;CAC1C,MAAM,YAAY,sBAAsB,OAAO,QAAQ,SAAS,QAAQ;CAExE,MAAM,OAAO,YAAY,WAAW,oBAAC,gBAAD,EAAwB,OAAS,CAAA,GAAG;EACtE,GAAG;EACH;CACF,CAAC;CACD,OAAO,OAAO,EAAE;CAChB,OAAO;EAAE;EAAM;CAAO;AACxB;AAEA,eAAe,yBAAwC;CACrD,IAAI,OAAO,UAAU,KAAA,KAAa,SAAS,eAAe,WAAW;CACrE,MAAM,IAAI,SAAe,YACvB,SAAS,iBAAiB,0BAA0B,QAAQ,GAAG,EAC7D,MAAM,KACR,CAAC,CACH;AACF"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Container, FigRoot, FigRootOptions } from "@bgub/fig-dom";
|
|
2
|
+
import { AnyRouter } from "@tanstack/router-core";
|
|
3
|
+
//#region src/client.d.ts
|
|
4
|
+
interface HydrateStartOptions extends Omit<FigRootOptions, "dataPartition" | "dataStore" | "initialData"> {
|
|
5
|
+
container?: Container;
|
|
6
|
+
}
|
|
7
|
+
interface HydratedStart {
|
|
8
|
+
root: FigRoot;
|
|
9
|
+
router: AnyRouter;
|
|
10
|
+
}
|
|
11
|
+
declare function hydrateStart(options?: HydrateStartOptions): Promise<HydratedStart>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { HydrateStartOptions, HydratedStart, hydrateStart };
|
package/dist/client.js
ADDED
package/dist/data.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FigDataStoreController, FigNode } from "@bgub/fig";
|
|
2
|
+
import { RouteDataContext } from "@bgub/fig-tanstack-router";
|
|
3
|
+
import { createCsrfMiddleware, createMiddleware, createServerFn, createStart } from "@tanstack/start-client-core";
|
|
4
|
+
import { Register } from "@tanstack/router-core";
|
|
5
|
+
//#region src/data.d.ts
|
|
6
|
+
interface StartDataContext extends RouteDataContext {
|
|
7
|
+
data: FigDataStoreController;
|
|
8
|
+
}
|
|
9
|
+
declare function createStartDataContext(): {
|
|
10
|
+
context: StartDataContext;
|
|
11
|
+
};
|
|
12
|
+
declare function StartScripts(): FigNode;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { type Register, StartDataContext, StartScripts, createCsrfMiddleware, createMiddleware, createServerFn, createStart, createStartDataContext };
|
package/dist/data.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { a as payloadTransportMarkerId } from "./payload-internal-CZhfVhwH.js";
|
|
2
|
+
import { t as requireStartDataStore } from "./store-CibAGqiI.js";
|
|
3
|
+
import { i as startDataScriptId, r as serializeStartDataStore, t as createStartDataStore } from "./transport-DKcSG44e.js";
|
|
4
|
+
import { createElement } from "@bgub/fig";
|
|
5
|
+
import { HYDRATION_SKIP_ATTRIBUTE } from "@bgub/fig/internal";
|
|
6
|
+
import { Scripts, useRouter } from "@bgub/fig-tanstack-router";
|
|
7
|
+
import { createCsrfMiddleware, createMiddleware, createServerFn, createStart } from "@tanstack/start-client-core";
|
|
8
|
+
//#region src/data.ts
|
|
9
|
+
function createStartDataContext() {
|
|
10
|
+
return { context: { data: createStartDataStore() } };
|
|
11
|
+
}
|
|
12
|
+
function StartScripts() {
|
|
13
|
+
const router = useRouter();
|
|
14
|
+
const routerScripts = createElement(Scripts);
|
|
15
|
+
if (!router.isServer) return routerScripts;
|
|
16
|
+
const dataStore = requireStartDataStore(router.options.context);
|
|
17
|
+
return [
|
|
18
|
+
createElement("script", {
|
|
19
|
+
[HYDRATION_SKIP_ATTRIBUTE]: true,
|
|
20
|
+
id: startDataScriptId,
|
|
21
|
+
type: "application/json",
|
|
22
|
+
unsafeHTML: serializeStartDataStore(dataStore)
|
|
23
|
+
}),
|
|
24
|
+
createElement("template", {
|
|
25
|
+
id: payloadTransportMarkerId,
|
|
26
|
+
[HYDRATION_SKIP_ATTRIBUTE]: true
|
|
27
|
+
}),
|
|
28
|
+
routerScripts
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { StartScripts, createCsrfMiddleware, createMiddleware, createServerFn, createStart, createStartDataContext };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=data.js.map
|
package/dist/data.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.js","names":["RouterScripts"],"sources":["../src/data.ts"],"sourcesContent":["import {\n createElement,\n type FigDataStoreController,\n type FigNode,\n} from \"@bgub/fig\";\nimport { HYDRATION_SKIP_ATTRIBUTE } from \"@bgub/fig/internal\";\nimport {\n type AnyRouter,\n type RouteDataContext,\n Scripts as RouterScripts,\n useRouter,\n} from \"@bgub/fig-tanstack-router\";\nimport { payloadTransportMarkerId } from \"./document-markers.ts\";\nimport { requireStartDataStore } from \"./store.ts\";\nimport {\n createStartDataStore,\n serializeStartDataStore,\n startDataScriptId,\n} from \"./transport.ts\";\n\nexport {\n createCsrfMiddleware,\n createMiddleware,\n createServerFn,\n createStart,\n} from \"@tanstack/start-client-core\";\nexport type { Register } from \"@tanstack/router-core\";\n\nexport interface StartDataContext extends RouteDataContext {\n data: FigDataStoreController;\n}\n\nexport function createStartDataContext(): { context: StartDataContext } {\n return {\n context: {\n data: createStartDataStore(),\n },\n };\n}\n\nexport function StartScripts(): FigNode {\n const router = useRouter<AnyRouter>();\n const routerScripts = createElement(RouterScripts);\n if (!router.isServer) return routerScripts;\n\n const dataStore = requireStartDataStore(router.options.context);\n return [\n createElement(\"script\", {\n [HYDRATION_SKIP_ATTRIBUTE]: true,\n id: startDataScriptId,\n type: \"application/json\",\n unsafeHTML: serializeStartDataStore(dataStore),\n }),\n createElement(\"template\", {\n id: payloadTransportMarkerId,\n [HYDRATION_SKIP_ATTRIBUTE]: true,\n }),\n routerScripts,\n ];\n}\n"],"mappings":";;;;;;;;AAgCA,SAAgB,yBAAwD;CACtE,OAAO,EACL,SAAS,EACP,MAAM,qBAAqB,EAC7B,EACF;AACF;AAEA,SAAgB,eAAwB;CACtC,MAAM,SAAS,UAAqB;CACpC,MAAM,gBAAgB,cAAcA,OAAa;CACjD,IAAI,CAAC,OAAO,UAAU,OAAO;CAE7B,MAAM,YAAY,sBAAsB,OAAO,QAAQ,OAAO;CAC9D,OAAO;EACL,cAAc,UAAU;IACrB,2BAA2B;GAC5B,IAAI;GACJ,MAAM;GACN,YAAY,wBAAwB,SAAS;EAC/C,CAAC;EACD,cAAc,YAAY;GACxB,IAAI;IACH,2BAA2B;EAC9B,CAAC;EACD;CACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../src/default-entry/client.ts"],"sourcesContent":["import { hydrateStart } from \"../client.tsx\";\n\nawait hydrateStart();\n"],"mappings":";;AAEA,MAAM,aAAa"}
|