@tanstack/start-server-core 1.168.0 → 1.168.1
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/esm/createStartHandler.d.ts +2 -133
- package/dist/esm/createStartHandler.js +27 -154
- package/dist/esm/createStartHandler.js.map +1 -1
- package/dist/esm/early-hints.d.ts +12 -0
- package/dist/esm/early-hints.js +87 -1
- package/dist/esm/early-hints.js.map +1 -1
- package/dist/esm/finalManifest.d.ts +42 -0
- package/dist/esm/finalManifest.js +126 -0
- package/dist/esm/finalManifest.js.map +1 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/inlineCss.d.ts +10 -0
- package/dist/esm/inlineCss.js +14 -0
- package/dist/esm/inlineCss.js.map +1 -0
- package/dist/esm/request-handler.d.ts +11 -1
- package/dist/esm/transformAssetUrls.d.ts +25 -48
- package/dist/esm/transformAssetUrls.js +41 -34
- package/dist/esm/transformAssetUrls.js.map +1 -1
- package/package.json +4 -4
- package/skills/start-server-core/SKILL.md +1 -1
- package/src/createStartHandler.ts +43 -465
- package/src/early-hints.ts +159 -0
- package/src/finalManifest.ts +319 -0
- package/src/index.tsx +1 -5
- package/src/inlineCss.ts +31 -0
- package/src/request-handler.ts +12 -0
- package/src/transformAssetUrls.ts +118 -121
|
@@ -24,19 +24,11 @@ import {
|
|
|
24
24
|
import { requestHandler } from './request-response'
|
|
25
25
|
import { getStartManifest } from './router-manifest'
|
|
26
26
|
import { handleServerAction } from './server-functions-handler'
|
|
27
|
+
import { createEarlyHintsCollector } from './early-hints'
|
|
27
28
|
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
transformManifestAssets,
|
|
32
|
-
} from './transformAssetUrls'
|
|
33
|
-
import {
|
|
34
|
-
collectDynamicHintsFromMatches,
|
|
35
|
-
collectStaticHintsFromManifest,
|
|
36
|
-
createEarlyHintsEvent,
|
|
37
|
-
createResponseLinkHeaderEntries,
|
|
38
|
-
getResponseLinkHeaderEntries,
|
|
39
|
-
} from './early-hints'
|
|
29
|
+
createCachedBaseManifestLoader,
|
|
30
|
+
createFinalManifestResolver,
|
|
31
|
+
} from './finalManifest'
|
|
40
32
|
|
|
41
33
|
import { HEADERS } from './constants'
|
|
42
34
|
import { ServerFunctionSerializationAdapter } from './serializer/ServerFunctionSerializationAdapter'
|
|
@@ -50,29 +42,14 @@ import type {
|
|
|
50
42
|
StartEntry,
|
|
51
43
|
} from '@tanstack/start-client-core'
|
|
52
44
|
import type { RequestHandler } from './request-handler'
|
|
53
|
-
import type {
|
|
54
|
-
EarlyHint,
|
|
55
|
-
EarlyHintsEvent,
|
|
56
|
-
EarlyHintsPhase,
|
|
57
|
-
OnEarlyHints,
|
|
58
|
-
ResponseLinkHeaderEntry,
|
|
59
|
-
ResponseLinkHeaderFilter,
|
|
60
|
-
ResponseLinkHeaderOptions,
|
|
61
|
-
} from './early-hints'
|
|
62
45
|
import type {
|
|
63
46
|
AnyRoute,
|
|
64
47
|
AnyRouter,
|
|
65
48
|
AnySerializationAdapter,
|
|
66
|
-
Manifest,
|
|
67
49
|
Register,
|
|
68
50
|
} from '@tanstack/router-core'
|
|
69
51
|
import type { HandlerCallback } from '@tanstack/router-core/ssr/server'
|
|
70
|
-
import type {
|
|
71
|
-
StartManifestWithClientEntry,
|
|
72
|
-
TransformAssetUrls,
|
|
73
|
-
TransformAssets,
|
|
74
|
-
TransformAssetsFn,
|
|
75
|
-
} from './transformAssetUrls'
|
|
52
|
+
import type { FinalManifestOptions } from './finalManifest'
|
|
76
53
|
|
|
77
54
|
type TODO = any
|
|
78
55
|
|
|
@@ -80,139 +57,8 @@ type AnyMiddlewareServerFn =
|
|
|
80
57
|
| AnyRequestMiddleware['options']['server']
|
|
81
58
|
| AnyFunctionMiddleware['options']['server']
|
|
82
59
|
|
|
83
|
-
export interface CreateStartHandlerOptions {
|
|
60
|
+
export interface CreateStartHandlerOptions extends FinalManifestOptions {
|
|
84
61
|
handler: HandlerCallback<AnyRouter>
|
|
85
|
-
/**
|
|
86
|
-
* Transform asset URLs and attributes at runtime, e.g. to prepend a CDN prefix.
|
|
87
|
-
*
|
|
88
|
-
* **String** — a URL prefix prepended to every asset URL (cached by default):
|
|
89
|
-
* ```ts
|
|
90
|
-
* createStartHandler({
|
|
91
|
-
* handler: defaultStreamHandler,
|
|
92
|
-
* transformAssets: 'https://cdn.example.com',
|
|
93
|
-
* })
|
|
94
|
-
* ```
|
|
95
|
-
*
|
|
96
|
-
* **Object shorthand** — a URL prefix with optional `crossOrigin`:
|
|
97
|
-
* ```ts
|
|
98
|
-
* createStartHandler({
|
|
99
|
-
* handler: defaultStreamHandler,
|
|
100
|
-
* transformAssets: {
|
|
101
|
-
* prefix: 'https://cdn.example.com',
|
|
102
|
-
* crossOrigin: 'anonymous',
|
|
103
|
-
* },
|
|
104
|
-
* })
|
|
105
|
-
* ```
|
|
106
|
-
*
|
|
107
|
-
* `crossOrigin` accepts a single value or a per-kind record:
|
|
108
|
-
* ```ts
|
|
109
|
-
* transformAssets: {
|
|
110
|
-
* prefix: 'https://cdn.example.com',
|
|
111
|
-
* crossOrigin: {
|
|
112
|
-
* modulepreload: 'anonymous',
|
|
113
|
-
* stylesheet: 'use-credentials',
|
|
114
|
-
* },
|
|
115
|
-
* }
|
|
116
|
-
* ```
|
|
117
|
-
*
|
|
118
|
-
* **Callback** — receives `{ kind, url }` and returns either a string URL or
|
|
119
|
-
* `{ href, crossOrigin? }` (cached by default — runs once on first request):
|
|
120
|
-
* ```ts
|
|
121
|
-
* createStartHandler({
|
|
122
|
-
* handler: defaultStreamHandler,
|
|
123
|
-
* transformAssets: ({ kind, url }) => {
|
|
124
|
-
* const href = `https://cdn.example.com${url}`
|
|
125
|
-
*
|
|
126
|
-
* if (kind === 'modulepreload') {
|
|
127
|
-
* return { href, crossOrigin: 'anonymous' }
|
|
128
|
-
* }
|
|
129
|
-
*
|
|
130
|
-
* return { href }
|
|
131
|
-
* },
|
|
132
|
-
* })
|
|
133
|
-
* ```
|
|
134
|
-
*
|
|
135
|
-
* **Object** — for explicit cache control:
|
|
136
|
-
* ```ts
|
|
137
|
-
* createStartHandler({
|
|
138
|
-
* handler: defaultStreamHandler,
|
|
139
|
-
* transformAssets: {
|
|
140
|
-
* transform: ({ url }) => {
|
|
141
|
-
* const region = getRequest().headers.get('x-region') || 'us'
|
|
142
|
-
* return { href: `https://cdn-${region}.example.com${url}` }
|
|
143
|
-
* },
|
|
144
|
-
* cache: false,
|
|
145
|
-
* },
|
|
146
|
-
* })
|
|
147
|
-
* ```
|
|
148
|
-
*
|
|
149
|
-
* `kind` is one of `'modulepreload' | 'stylesheet' | 'clientEntry'`.
|
|
150
|
-
* `crossOrigin` applies to manifest-managed `<link>` assets.
|
|
151
|
-
*
|
|
152
|
-
* By default, the transformed manifest is cached after the first request
|
|
153
|
-
* (`cache: true`). Set `cache: false` for per-request transforms.
|
|
154
|
-
*
|
|
155
|
-
* If you're using a cached transform, you can optionally set `warmup: true`
|
|
156
|
-
* (object form only) to compute the transformed manifest in the background at
|
|
157
|
-
* server startup.
|
|
158
|
-
*
|
|
159
|
-
* Note: This only transforms URLs managed by TanStack Start's manifest
|
|
160
|
-
* (JS preloads, CSS links, and the client entry script). For asset imports
|
|
161
|
-
* used directly in components (e.g. `import logo from './logo.svg'`),
|
|
162
|
-
* configure Vite's `experimental.renderBuiltUrl` in your vite.config.ts.
|
|
163
|
-
*/
|
|
164
|
-
transformAssets?: TransformAssets
|
|
165
|
-
/**
|
|
166
|
-
* @deprecated Use `transformAssets` instead.
|
|
167
|
-
*
|
|
168
|
-
* **String** — a URL prefix prepended to every asset URL (cached by default):
|
|
169
|
-
* ```ts
|
|
170
|
-
* createStartHandler({
|
|
171
|
-
* handler: defaultStreamHandler,
|
|
172
|
-
* transformAssetUrls: 'https://cdn.example.com',
|
|
173
|
-
* })
|
|
174
|
-
* ```
|
|
175
|
-
*
|
|
176
|
-
* **Callback** — receives `{ url, type }` and returns a new URL
|
|
177
|
-
* (cached by default — runs once on first request):
|
|
178
|
-
* ```ts
|
|
179
|
-
* createStartHandler({
|
|
180
|
-
* handler: defaultStreamHandler,
|
|
181
|
-
* transformAssetUrls: ({ url, type }) => {
|
|
182
|
-
* return `https://cdn.example.com${url}`
|
|
183
|
-
* },
|
|
184
|
-
* })
|
|
185
|
-
* ```
|
|
186
|
-
*
|
|
187
|
-
* **Object** — for explicit cache control:
|
|
188
|
-
* ```ts
|
|
189
|
-
* createStartHandler({
|
|
190
|
-
* handler: defaultStreamHandler,
|
|
191
|
-
* transformAssetUrls: {
|
|
192
|
-
* transform: ({ url }) => {
|
|
193
|
-
* const region = getRequest().headers.get('x-region') || 'us'
|
|
194
|
-
* return `https://cdn-${region}.example.com${url}`
|
|
195
|
-
* },
|
|
196
|
-
* cache: false, // transform per-request
|
|
197
|
-
* },
|
|
198
|
-
* })
|
|
199
|
-
* ```
|
|
200
|
-
*
|
|
201
|
-
* `type` is one of `'modulepreload' | 'stylesheet' | 'clientEntry'`.
|
|
202
|
-
*
|
|
203
|
-
* By default, the transformed manifest is cached after the first request
|
|
204
|
-
* (`cache: true`). Set `cache: false` for per-request transforms.
|
|
205
|
-
*
|
|
206
|
-
* If you're using a cached transform, you can optionally set `warmup: true`
|
|
207
|
-
* (object form only) to compute the transformed manifest in the background at
|
|
208
|
-
* server startup.
|
|
209
|
-
*
|
|
210
|
-
* Note: This only transforms URLs managed by TanStack Start's manifest
|
|
211
|
-
* (JS preloads, CSS links, and the client entry script). For asset imports
|
|
212
|
-
* used directly in components (e.g. `import logo from './logo.svg'`),
|
|
213
|
-
* configure Vite's `experimental.renderBuiltUrl` in your vite.config.ts.
|
|
214
|
-
*/
|
|
215
|
-
transformAssetUrls?: TransformAssetUrls
|
|
216
62
|
}
|
|
217
63
|
|
|
218
64
|
function getStartResponseHeaders(opts: { router: AnyRouter }) {
|
|
@@ -227,106 +73,6 @@ function getStartResponseHeaders(opts: { router: AnyRouter }) {
|
|
|
227
73
|
return headers
|
|
228
74
|
}
|
|
229
75
|
|
|
230
|
-
function notifyEarlyHints(
|
|
231
|
-
phase: EarlyHintsPhase,
|
|
232
|
-
event: EarlyHintsEvent,
|
|
233
|
-
onEarlyHints: OnEarlyHints,
|
|
234
|
-
) {
|
|
235
|
-
try {
|
|
236
|
-
const result = onEarlyHints(event)
|
|
237
|
-
if (result) {
|
|
238
|
-
void Promise.resolve(result).catch((err) => {
|
|
239
|
-
console.error(`Error sending ${phase} early hints:`, err)
|
|
240
|
-
})
|
|
241
|
-
}
|
|
242
|
-
} catch (err) {
|
|
243
|
-
console.error(`Error sending ${phase} early hints:`, err)
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function getResponseLinkHeaderFilter(
|
|
248
|
-
responseLinkHeader: boolean | ResponseLinkHeaderOptions | undefined,
|
|
249
|
-
): ResponseLinkHeaderFilter | undefined {
|
|
250
|
-
if (typeof responseLinkHeader !== 'object') {
|
|
251
|
-
return undefined
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return responseLinkHeader.filter
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function appendResponseLinkHeaders(opts: {
|
|
258
|
-
responseHeaders: Headers
|
|
259
|
-
entries: ReadonlyArray<ResponseLinkHeaderEntry>
|
|
260
|
-
filter?: ResponseLinkHeaderFilter
|
|
261
|
-
}) {
|
|
262
|
-
if (!opts.filter) {
|
|
263
|
-
for (const entry of opts.entries) {
|
|
264
|
-
opts.responseHeaders.append('Link', entry.link)
|
|
265
|
-
}
|
|
266
|
-
return
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const links = getResponseLinkHeaderEntries(opts)
|
|
270
|
-
|
|
271
|
-
for (const link of links) {
|
|
272
|
-
opts.responseHeaders.append('Link', link)
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function collectResponseLinkHeaderEntries(opts: {
|
|
277
|
-
phase: EarlyHintsPhase
|
|
278
|
-
event: EarlyHintsEvent
|
|
279
|
-
entries: Array<ResponseLinkHeaderEntry>
|
|
280
|
-
}) {
|
|
281
|
-
for (let index = 0; index < opts.event.hints.length; index++) {
|
|
282
|
-
opts.entries.push({
|
|
283
|
-
phase: opts.phase,
|
|
284
|
-
hint: opts.event.hints[index]!,
|
|
285
|
-
link: opts.event.links[index]!,
|
|
286
|
-
})
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function handleCollectedEarlyHints(opts: {
|
|
291
|
-
phase: EarlyHintsPhase
|
|
292
|
-
hints: ReadonlyArray<EarlyHint>
|
|
293
|
-
sentLinks: Set<string>
|
|
294
|
-
sentHints?: Array<EarlyHint>
|
|
295
|
-
onEarlyHints?: OnEarlyHints
|
|
296
|
-
responseLinkHeaderEntries?: Array<ResponseLinkHeaderEntry>
|
|
297
|
-
}) {
|
|
298
|
-
const event = opts.onEarlyHints
|
|
299
|
-
? createEarlyHintsEvent({
|
|
300
|
-
phase: opts.phase,
|
|
301
|
-
hints: opts.hints,
|
|
302
|
-
sentLinks: opts.sentLinks,
|
|
303
|
-
sentHints: opts.sentHints!,
|
|
304
|
-
})
|
|
305
|
-
: undefined
|
|
306
|
-
|
|
307
|
-
if (event) {
|
|
308
|
-
notifyEarlyHints(opts.phase, event, opts.onEarlyHints!)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (!opts.responseLinkHeaderEntries) return
|
|
312
|
-
|
|
313
|
-
if (event) {
|
|
314
|
-
collectResponseLinkHeaderEntries({
|
|
315
|
-
phase: opts.phase,
|
|
316
|
-
event,
|
|
317
|
-
entries: opts.responseLinkHeaderEntries,
|
|
318
|
-
})
|
|
319
|
-
return
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
createResponseLinkHeaderEntries({
|
|
323
|
-
phase: opts.phase,
|
|
324
|
-
hints: opts.hints,
|
|
325
|
-
sentLinks: opts.sentLinks,
|
|
326
|
-
entries: opts.responseLinkHeaderEntries,
|
|
327
|
-
})
|
|
328
|
-
}
|
|
329
|
-
|
|
330
76
|
interface PluginAdaptersEntry {
|
|
331
77
|
hasPluginAdapters: boolean
|
|
332
78
|
pluginSerializationAdapters: Array<AnySerializationAdapter>
|
|
@@ -341,17 +87,21 @@ interface Entries {
|
|
|
341
87
|
// Cached entries - promises stored immediately to prevent concurrent imports
|
|
342
88
|
// that can cause race conditions during module initialization
|
|
343
89
|
let entriesPromise: Promise<Entries> | undefined
|
|
344
|
-
let baseManifestPromise: Promise<StartManifestWithClientEntry> | undefined
|
|
345
90
|
let hasWarnedMissingCsrfMiddleware = false
|
|
346
91
|
const defaultCsrfMiddleware = createCsrfMiddleware({
|
|
347
92
|
filter: (ctx) => ctx.handlerType === 'serverFn',
|
|
348
93
|
})
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
94
|
+
const getCachedBaseManifest = createCachedBaseManifestLoader(() =>
|
|
95
|
+
getStartManifest(),
|
|
96
|
+
)
|
|
97
|
+
const getProdBaseManifest: typeof getStartManifest = () =>
|
|
98
|
+
getCachedBaseManifest()
|
|
99
|
+
const getBaseManifest =
|
|
100
|
+
process.env.TSS_DEV_SERVER === 'true' ? getStartManifest : getProdBaseManifest
|
|
101
|
+
const createEarlyHintsForRequest: typeof createEarlyHintsCollector =
|
|
102
|
+
process.env.TSS_DEV_SERVER === 'true'
|
|
103
|
+
? () => undefined
|
|
104
|
+
: createEarlyHintsCollector
|
|
355
105
|
|
|
356
106
|
async function loadEntries(): Promise<Entries> {
|
|
357
107
|
const [routerEntry, startEntry, pluginAdapters] = await Promise.all([
|
|
@@ -409,61 +159,6 @@ If you intentionally handle CSRF another way, disable this warning:
|
|
|
409
159
|
})`)
|
|
410
160
|
}
|
|
411
161
|
|
|
412
|
-
/**
|
|
413
|
-
* Returns the raw manifest data (without client entry script tag baked in).
|
|
414
|
-
* In dev mode, always returns fresh data. In prod, cached.
|
|
415
|
-
*/
|
|
416
|
-
function getBaseManifest(
|
|
417
|
-
matchedRoutes?: ReadonlyArray<AnyRoute>,
|
|
418
|
-
): Promise<StartManifestWithClientEntry> {
|
|
419
|
-
// In dev mode, always get fresh manifest (no caching) to include route-specific dev styles
|
|
420
|
-
if (process.env.TSS_DEV_SERVER === 'true') {
|
|
421
|
-
return getStartManifest(matchedRoutes)
|
|
422
|
-
}
|
|
423
|
-
// In prod, cache the base manifest
|
|
424
|
-
if (!baseManifestPromise) {
|
|
425
|
-
baseManifestPromise = getStartManifest()
|
|
426
|
-
}
|
|
427
|
-
return baseManifestPromise
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Resolves a final Manifest for a given request.
|
|
432
|
-
*
|
|
433
|
-
* - No transform: builds client entry script tag and returns (cached in prod).
|
|
434
|
-
* - Cached transform: transforms all URLs + builds script tag, caches result.
|
|
435
|
-
* - Per-request transform: deep-clones base manifest, transforms per-request.
|
|
436
|
-
*/
|
|
437
|
-
async function resolveManifest(
|
|
438
|
-
matchedRoutes: ReadonlyArray<AnyRoute> | undefined,
|
|
439
|
-
transformFn: TransformAssetsFn | undefined,
|
|
440
|
-
cache: boolean,
|
|
441
|
-
): Promise<Manifest> {
|
|
442
|
-
const base = await getBaseManifest(matchedRoutes)
|
|
443
|
-
|
|
444
|
-
const computeFinalManifest = async () => {
|
|
445
|
-
return transformFn
|
|
446
|
-
? await transformManifestAssets(base, transformFn, { clone: !cache })
|
|
447
|
-
: buildManifestWithClientEntry(base)
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// In dev, always compute fresh to include route-specific dev styles.
|
|
451
|
-
if (process.env.TSS_DEV_SERVER === 'true') {
|
|
452
|
-
return computeFinalManifest()
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// In prod, cache unless we're explicitly doing per-request transforms.
|
|
456
|
-
if (!transformFn || cache) {
|
|
457
|
-
if (!cachedFinalManifestPromise) {
|
|
458
|
-
cachedFinalManifestPromise = computeFinalManifest()
|
|
459
|
-
}
|
|
460
|
-
return cachedFinalManifestPromise
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Per-request transform — deep-clone and transform every time.
|
|
464
|
-
return computeFinalManifest()
|
|
465
|
-
}
|
|
466
|
-
|
|
467
162
|
// Pre-computed constants
|
|
468
163
|
const ROUTER_BASEPATH = process.env.TSS_ROUTER_BASEPATH || '/'
|
|
469
164
|
const SERVER_FN_BASE = process.env.TSS_SERVER_FN_BASE
|
|
@@ -608,96 +303,22 @@ function handlerToMiddleware(
|
|
|
608
303
|
export function createStartHandler<TRegister = Register>(
|
|
609
304
|
cbOrOptions: HandlerCallback<AnyRouter> | CreateStartHandlerOptions,
|
|
610
305
|
): RequestHandler<TRegister> {
|
|
611
|
-
|
|
306
|
+
const handlerOptions: FinalManifestOptions =
|
|
307
|
+
typeof cbOrOptions === 'function' ? {} : cbOrOptions
|
|
612
308
|
const cb: HandlerCallback<AnyRouter> =
|
|
613
309
|
typeof cbOrOptions === 'function' ? cbOrOptions : cbOrOptions.handler
|
|
614
|
-
const
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
adaptTransformAssetUrlsConfigToTransformAssets(
|
|
627
|
-
transformAssetUrlsOption,
|
|
628
|
-
),
|
|
629
|
-
)
|
|
630
|
-
: undefined
|
|
631
|
-
|
|
632
|
-
const warmupTransformManifest =
|
|
633
|
-
(!!transformAssetsOption &&
|
|
634
|
-
typeof transformAssetsOption === 'object' &&
|
|
635
|
-
'warmup' in transformAssetsOption &&
|
|
636
|
-
transformAssetsOption.warmup === true) ||
|
|
637
|
-
(!!transformAssetUrlsOption &&
|
|
638
|
-
typeof transformAssetUrlsOption === 'object' &&
|
|
639
|
-
transformAssetUrlsOption.warmup === true)
|
|
640
|
-
|
|
641
|
-
// Pre-resolve the transform function and cache flag
|
|
642
|
-
const resolvedTransformConfig = transformOption
|
|
643
|
-
const cache = resolvedTransformConfig ? resolvedTransformConfig.cache : true
|
|
644
|
-
const shouldCacheCreateTransform =
|
|
645
|
-
cache && process.env.TSS_DEV_SERVER !== 'true'
|
|
646
|
-
|
|
647
|
-
// Memoize a single createTransform() result when caching is enabled outside
|
|
648
|
-
// of the dev server.
|
|
649
|
-
let cachedCreateTransformPromise: Promise<TransformAssetsFn> | undefined
|
|
650
|
-
|
|
651
|
-
const getTransformFn = async (
|
|
652
|
-
opts: { warmup: true } | { warmup: false; request: Request },
|
|
653
|
-
): Promise<TransformAssetsFn | undefined> => {
|
|
654
|
-
if (!resolvedTransformConfig) return undefined
|
|
655
|
-
|
|
656
|
-
if (resolvedTransformConfig.type === 'createTransform') {
|
|
657
|
-
if (shouldCacheCreateTransform) {
|
|
658
|
-
if (!cachedCreateTransformPromise) {
|
|
659
|
-
cachedCreateTransformPromise = Promise.resolve(
|
|
660
|
-
resolvedTransformConfig.createTransform(opts),
|
|
661
|
-
).catch((error) => {
|
|
662
|
-
cachedCreateTransformPromise = undefined
|
|
663
|
-
throw error
|
|
664
|
-
})
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
return cachedCreateTransformPromise
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
return resolvedTransformConfig.createTransform(opts)
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
return resolvedTransformConfig.transformFn
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
// Background warmup for cached transforms (production only)
|
|
677
|
-
if (
|
|
678
|
-
warmupTransformManifest &&
|
|
679
|
-
cache &&
|
|
680
|
-
process.env.TSS_DEV_SERVER !== 'true' &&
|
|
681
|
-
!cachedFinalManifestPromise
|
|
682
|
-
) {
|
|
683
|
-
// NOTE: Do not call resolveManifest() here.
|
|
684
|
-
// resolveManifest() reads from cachedFinalManifestPromise, and since we set
|
|
685
|
-
// cachedFinalManifestPromise to this warmup promise, that would create a
|
|
686
|
-
// self-referential promise and hang forever.
|
|
687
|
-
const warmupPromise = (async () => {
|
|
688
|
-
const base = await getBaseManifest(undefined)
|
|
689
|
-
const transformFn = await getTransformFn({ warmup: true })
|
|
690
|
-
return transformFn
|
|
691
|
-
? await transformManifestAssets(base, transformFn, { clone: false })
|
|
692
|
-
: buildManifestWithClientEntry(base)
|
|
693
|
-
})()
|
|
694
|
-
cachedFinalManifestPromise = warmupPromise
|
|
695
|
-
warmupPromise.catch(() => {
|
|
696
|
-
// If warmup fails, allow the next request to retry.
|
|
697
|
-
if (cachedFinalManifestPromise === warmupPromise) {
|
|
698
|
-
cachedFinalManifestPromise = undefined
|
|
699
|
-
}
|
|
700
|
-
cachedCreateTransformPromise = undefined
|
|
310
|
+
const finalManifestResolver = createFinalManifestResolver({
|
|
311
|
+
...handlerOptions,
|
|
312
|
+
cacheCreateTransform: process.env.TSS_DEV_SERVER !== 'true',
|
|
313
|
+
})
|
|
314
|
+
const resolveManifestForRequest =
|
|
315
|
+
process.env.TSS_DEV_SERVER === 'true'
|
|
316
|
+
? finalManifestResolver.resolveUncached
|
|
317
|
+
: finalManifestResolver.resolveCached
|
|
318
|
+
|
|
319
|
+
if (process.env.TSS_DEV_SERVER !== 'true') {
|
|
320
|
+
finalManifestResolver.warmup({
|
|
321
|
+
getBaseManifest: () => getBaseManifest(undefined),
|
|
701
322
|
})
|
|
702
323
|
}
|
|
703
324
|
|
|
@@ -856,44 +477,18 @@ export function createStartHandler<TRegister = Register>(
|
|
|
856
477
|
)
|
|
857
478
|
}
|
|
858
479
|
|
|
859
|
-
const manifest = await
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
)
|
|
480
|
+
const manifest = await resolveManifestForRequest({
|
|
481
|
+
request,
|
|
482
|
+
requestInlineCss: requestOpts?.inlineCss,
|
|
483
|
+
getBaseManifest: () => getBaseManifest(matchedRoutes),
|
|
484
|
+
})
|
|
864
485
|
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
(!!onEarlyHints || !!responseLinkHeader)
|
|
870
|
-
const sentEarlyHintLinks = shouldCollectEarlyHints
|
|
871
|
-
? new Set<string>()
|
|
872
|
-
: undefined
|
|
873
|
-
const sentEarlyHints = onEarlyHints ? new Array<EarlyHint>() : undefined
|
|
874
|
-
const responseLinkHeaderEntries =
|
|
875
|
-
shouldCollectEarlyHints && responseLinkHeader
|
|
876
|
-
? new Array<ResponseLinkHeaderEntry>()
|
|
877
|
-
: undefined
|
|
878
|
-
const responseLinkHeaderFilter = shouldCollectEarlyHints
|
|
879
|
-
? getResponseLinkHeaderFilter(responseLinkHeader)
|
|
880
|
-
: undefined
|
|
486
|
+
const earlyHints = createEarlyHintsForRequest({
|
|
487
|
+
onEarlyHints: requestOpts?.onEarlyHints,
|
|
488
|
+
responseLinkHeader: requestOpts?.responseLinkHeader,
|
|
489
|
+
})
|
|
881
490
|
|
|
882
|
-
|
|
883
|
-
shouldCollectEarlyHints &&
|
|
884
|
-
sentEarlyHintLinks &&
|
|
885
|
-
matchedRoutes?.length
|
|
886
|
-
) {
|
|
887
|
-
const hints = collectStaticHintsFromManifest(manifest, matchedRoutes)
|
|
888
|
-
handleCollectedEarlyHints({
|
|
889
|
-
phase: 'static',
|
|
890
|
-
hints,
|
|
891
|
-
sentLinks: sentEarlyHintLinks,
|
|
892
|
-
sentHints: sentEarlyHints,
|
|
893
|
-
onEarlyHints,
|
|
894
|
-
responseLinkHeaderEntries,
|
|
895
|
-
})
|
|
896
|
-
}
|
|
491
|
+
earlyHints?.collectStatic({ manifest, matchedRoutes })
|
|
897
492
|
|
|
898
493
|
const routerInstance = await getRouter()
|
|
899
494
|
|
|
@@ -912,18 +507,7 @@ export function createStartHandler<TRegister = Register>(
|
|
|
912
507
|
return routerInstance.state.redirect
|
|
913
508
|
}
|
|
914
509
|
|
|
915
|
-
|
|
916
|
-
const loadedMatches = routerInstance.stores.matches.get()
|
|
917
|
-
const hints = collectDynamicHintsFromMatches(loadedMatches)
|
|
918
|
-
handleCollectedEarlyHints({
|
|
919
|
-
phase: 'dynamic',
|
|
920
|
-
hints,
|
|
921
|
-
sentLinks: sentEarlyHintLinks,
|
|
922
|
-
sentHints: sentEarlyHints,
|
|
923
|
-
onEarlyHints,
|
|
924
|
-
responseLinkHeaderEntries,
|
|
925
|
-
})
|
|
926
|
-
}
|
|
510
|
+
earlyHints?.collectDynamic(routerInstance.stores.matches.get())
|
|
927
511
|
|
|
928
512
|
// Pass request-scoped assets to dehydrate for manifest injection
|
|
929
513
|
const ctx = getStartContext({ throwIfNotFound: false })
|
|
@@ -934,13 +518,7 @@ export function createStartHandler<TRegister = Register>(
|
|
|
934
518
|
const responseHeaders = getStartResponseHeaders({
|
|
935
519
|
router: routerInstance,
|
|
936
520
|
})
|
|
937
|
-
|
|
938
|
-
appendResponseLinkHeaders({
|
|
939
|
-
responseHeaders,
|
|
940
|
-
entries: responseLinkHeaderEntries,
|
|
941
|
-
filter: responseLinkHeaderFilter,
|
|
942
|
-
})
|
|
943
|
-
}
|
|
521
|
+
earlyHints?.appendResponseHeaders(responseHeaders)
|
|
944
522
|
cbWillCleanup = true
|
|
945
523
|
|
|
946
524
|
return cb({
|