@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
package/dist/esm/early-hints.js
CHANGED
|
@@ -167,7 +167,93 @@ function getResponseLinkHeaderEntries(opts) {
|
|
|
167
167
|
return [];
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
+
function notifyEarlyHints(phase, event, onEarlyHints) {
|
|
171
|
+
try {
|
|
172
|
+
const result = onEarlyHints(event);
|
|
173
|
+
if (result) Promise.resolve(result).catch((err) => {
|
|
174
|
+
console.error(`Error sending ${phase} early hints:`, err);
|
|
175
|
+
});
|
|
176
|
+
} catch (err) {
|
|
177
|
+
console.error(`Error sending ${phase} early hints:`, err);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function getResponseLinkHeaderFilter(responseLinkHeader) {
|
|
181
|
+
if (typeof responseLinkHeader !== "object") return;
|
|
182
|
+
return responseLinkHeader.filter;
|
|
183
|
+
}
|
|
184
|
+
function appendResponseLinkHeaders(opts) {
|
|
185
|
+
for (const link of getResponseLinkHeaderEntries(opts)) opts.responseHeaders.append("Link", link);
|
|
186
|
+
}
|
|
187
|
+
function collectResponseLinkHeaderEntries(opts) {
|
|
188
|
+
for (let index = 0; index < opts.event.hints.length; index++) opts.entries.push({
|
|
189
|
+
phase: opts.phase,
|
|
190
|
+
hint: opts.event.hints[index],
|
|
191
|
+
link: opts.event.links[index]
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function collectEarlyHintsPhase(opts) {
|
|
195
|
+
const event = opts.onEarlyHints ? createEarlyHintsEvent({
|
|
196
|
+
phase: opts.phase,
|
|
197
|
+
hints: opts.hints,
|
|
198
|
+
sentLinks: opts.sentLinks,
|
|
199
|
+
sentHints: opts.sentHints
|
|
200
|
+
}) : void 0;
|
|
201
|
+
if (event) notifyEarlyHints(opts.phase, event, opts.onEarlyHints);
|
|
202
|
+
if (!opts.responseLinkHeaderEntries) return;
|
|
203
|
+
if (event) {
|
|
204
|
+
collectResponseLinkHeaderEntries({
|
|
205
|
+
phase: opts.phase,
|
|
206
|
+
event,
|
|
207
|
+
entries: opts.responseLinkHeaderEntries
|
|
208
|
+
});
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
createResponseLinkHeaderEntries({
|
|
212
|
+
phase: opts.phase,
|
|
213
|
+
hints: opts.hints,
|
|
214
|
+
sentLinks: opts.sentLinks,
|
|
215
|
+
entries: opts.responseLinkHeaderEntries
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
function createEarlyHintsCollector(opts) {
|
|
219
|
+
if (process.env.TSS_DEV_SERVER === "true" || !opts?.onEarlyHints && !opts?.responseLinkHeader) return;
|
|
220
|
+
const sentLinks = /* @__PURE__ */ new Set();
|
|
221
|
+
const sentHints = opts.onEarlyHints ? new Array() : void 0;
|
|
222
|
+
const responseLinkHeaderEntries = opts.responseLinkHeader ? new Array() : void 0;
|
|
223
|
+
const responseLinkHeaderFilter = getResponseLinkHeaderFilter(opts.responseLinkHeader);
|
|
224
|
+
return {
|
|
225
|
+
collectStatic: ({ manifest, matchedRoutes }) => {
|
|
226
|
+
if (!matchedRoutes?.length) return;
|
|
227
|
+
collectEarlyHintsPhase({
|
|
228
|
+
phase: "static",
|
|
229
|
+
hints: collectStaticHintsFromManifest(manifest, matchedRoutes),
|
|
230
|
+
sentLinks,
|
|
231
|
+
sentHints,
|
|
232
|
+
onEarlyHints: opts.onEarlyHints,
|
|
233
|
+
responseLinkHeaderEntries
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
collectDynamic: (matches) => {
|
|
237
|
+
collectEarlyHintsPhase({
|
|
238
|
+
phase: "dynamic",
|
|
239
|
+
hints: collectDynamicHintsFromMatches(matches),
|
|
240
|
+
sentLinks,
|
|
241
|
+
sentHints,
|
|
242
|
+
onEarlyHints: opts.onEarlyHints,
|
|
243
|
+
responseLinkHeaderEntries
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
appendResponseHeaders: (headers) => {
|
|
247
|
+
if (!responseLinkHeaderEntries?.length) return;
|
|
248
|
+
appendResponseLinkHeaders({
|
|
249
|
+
responseHeaders: headers,
|
|
250
|
+
entries: responseLinkHeaderEntries,
|
|
251
|
+
filter: responseLinkHeaderFilter
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
170
256
|
//#endregion
|
|
171
|
-
export {
|
|
257
|
+
export { createEarlyHintsCollector };
|
|
172
258
|
|
|
173
259
|
//# sourceMappingURL=early-hints.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"early-hints.js","names":[],"sources":["../../src/early-hints.ts"],"sourcesContent":["import {\n getStylesheetHref,\n resolveManifestAssetLink,\n} from '@tanstack/router-core'\nimport type {\n AnyRoute,\n AnyRouteMatch,\n AssetCrossOrigin,\n Manifest,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nexport type EarlyHint = {\n href: string\n rel: 'preload' | 'modulepreload' | 'preconnect' | 'dns-prefetch'\n as?: 'fetch' | 'font' | 'image' | 'script' | 'style' | 'track'\n crossOrigin?: AssetCrossOrigin | ''\n type?: string\n integrity?: string\n referrerPolicy?: string\n fetchPriority?: string\n}\n\nexport type EarlyHintsPhase = 'static' | 'dynamic'\n\nexport type EarlyHintsEvent = {\n phase: EarlyHintsPhase\n hints: ReadonlyArray<EarlyHint>\n links: Array<string>\n allHints: ReadonlyArray<EarlyHint>\n allLinks: Array<string>\n}\n\nexport type OnEarlyHints = (event: EarlyHintsEvent) => void | Promise<void>\n\nexport type ResponseLinkHeaderEntry = {\n phase: EarlyHintsPhase\n hint: EarlyHint\n link: string\n}\n\nexport type ResponseLinkHeaderFilter = (\n entry: ResponseLinkHeaderEntry,\n) => boolean\n\nexport type ResponseLinkHeaderOptions = {\n filter?: ResponseLinkHeaderFilter\n}\n\nconst LINK_PARAM_TOKEN_RE = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/\nconst PRELOAD_AS_VALUES = new Set<EarlyHint['as']>([\n 'fetch',\n 'font',\n 'image',\n 'script',\n 'style',\n 'track',\n])\n\nfunction buildLinkParam(name: string, value: string | undefined): string {\n if (value === undefined) return name\n if (LINK_PARAM_TOKEN_RE.test(value)) return `${name}=${value}`\n return `${name}=${JSON.stringify(value)}`\n}\n\nexport function serializeEarlyHint(hint: EarlyHint): string {\n const parts = [`<${hint.href}>`, buildLinkParam('rel', hint.rel)]\n if (hint.as) parts.push(buildLinkParam('as', hint.as))\n if (hint.crossOrigin !== undefined) {\n parts.push(buildLinkParam('crossorigin', hint.crossOrigin || undefined))\n }\n if (hint.type) parts.push(buildLinkParam('type', hint.type))\n if (hint.integrity) parts.push(buildLinkParam('integrity', hint.integrity))\n if (hint.referrerPolicy) {\n parts.push(buildLinkParam('referrerpolicy', hint.referrerPolicy))\n }\n if (hint.fetchPriority) {\n parts.push(buildLinkParam('fetchpriority', hint.fetchPriority))\n }\n return parts.join('; ')\n}\n\nfunction getStringAttr(\n attrs: Record<string, any> | undefined,\n name: string,\n fallbackName?: string,\n): string | undefined {\n const value =\n attrs?.[name] ?? (fallbackName ? attrs?.[fallbackName] : undefined)\n return typeof value === 'string' ? value : undefined\n}\n\nfunction getPreloadAs(\n attrs: Record<string, any> | undefined,\n): EarlyHint['as'] | undefined {\n const as = getStringAttr(attrs, 'as')\n return as && PRELOAD_AS_VALUES.has(as as EarlyHint['as'])\n ? (as as EarlyHint['as'])\n : undefined\n}\n\nfunction addEarlyHintFetchAttrs(\n hint: EarlyHint,\n attrs: Record<string, any> | undefined,\n) {\n const crossOrigin = getStringAttr(attrs, 'crossOrigin', 'crossorigin') as\n | EarlyHint['crossOrigin']\n | undefined\n const type = getStringAttr(attrs, 'type')\n const integrity = getStringAttr(attrs, 'integrity')\n const referrerPolicy = getStringAttr(\n attrs,\n 'referrerPolicy',\n 'referrerpolicy',\n )\n const fetchPriority = getStringAttr(attrs, 'fetchPriority', 'fetchpriority')\n\n if (crossOrigin !== undefined) hint.crossOrigin = crossOrigin\n if (type) hint.type = type\n if (integrity) hint.integrity = integrity\n if (referrerPolicy) hint.referrerPolicy = referrerPolicy\n if (fetchPriority) hint.fetchPriority = fetchPriority\n}\n\nfunction linkAttrsToEarlyHint(\n attrs: Record<string, any> | undefined,\n): EarlyHint | undefined {\n const href = getStringAttr(attrs, 'href')\n const rel = getStringAttr(attrs, 'rel')\n if (!href || !rel) return undefined\n\n const relTokens = rel.split(/\\s+/)\n let hintRel: EarlyHint['rel'] | undefined\n let hintAs: EarlyHint['as'] | undefined\n\n if (relTokens.includes('modulepreload')) {\n hintRel = 'modulepreload'\n hintAs = 'script'\n } else if (relTokens.includes('stylesheet')) {\n hintRel = 'preload'\n hintAs = 'style'\n } else if (relTokens.includes('preload')) {\n hintAs = getPreloadAs(attrs)\n if (!hintAs) return undefined\n hintRel = 'preload'\n } else if (relTokens.includes('preconnect')) {\n hintRel = 'preconnect'\n hintAs = undefined\n } else if (relTokens.includes('dns-prefetch')) {\n hintRel = 'dns-prefetch'\n hintAs = undefined\n }\n\n if (!hintRel) return undefined\n\n const hint: EarlyHint = {\n href,\n rel: hintRel,\n }\n\n if (hintAs) hint.as = hintAs\n addEarlyHintFetchAttrs(hint, attrs)\n\n return hint\n}\n\nexport function collectStaticHintsFromManifest(\n manifest: Manifest,\n matchedRoutes: ReadonlyArray<AnyRoute>,\n): Array<EarlyHint> {\n const hints: Array<EarlyHint> = []\n\n for (const route of matchedRoutes) {\n const routeManifest = manifest.routes[route.id]\n if (!routeManifest) continue\n\n for (const link of routeManifest.preloads ?? []) {\n const { href, crossOrigin } = resolveManifestAssetLink(link)\n const hint: EarlyHint = { href, rel: 'modulepreload', as: 'script' }\n if (crossOrigin !== undefined) hint.crossOrigin = crossOrigin\n hints.push(hint)\n }\n\n for (const asset of routeManifest.assets ?? []) {\n if (asset.tag !== 'link') continue\n\n const stylesheetHref = getStylesheetHref(asset)\n if (stylesheetHref) {\n if (manifest.inlineCss?.styles[stylesheetHref] !== undefined) continue\n\n const hint: EarlyHint = {\n href: stylesheetHref,\n rel: 'preload',\n as: 'style',\n }\n addEarlyHintFetchAttrs(hint, asset.attrs)\n hints.push(hint)\n continue\n }\n\n const hint = linkAttrsToEarlyHint(asset.attrs)\n if (hint) {\n hints.push(hint)\n }\n }\n }\n\n return hints\n}\n\nexport function collectDynamicHintsFromMatches(\n matches: ReadonlyArray<AnyRouteMatch>,\n): Array<EarlyHint> {\n const hints: Array<EarlyHint> = []\n\n for (const match of matches) {\n const links = match.links\n if (!Array.isArray(links)) continue\n\n for (const link of links as Array<RouterManagedTag['attrs']>) {\n const hint = linkAttrsToEarlyHint(link)\n if (hint) hints.push(hint)\n }\n }\n\n return hints\n}\n\nexport function createEarlyHintsEvent(opts: {\n phase: EarlyHintsPhase\n hints: ReadonlyArray<EarlyHint>\n sentLinks: Set<string>\n sentHints: Array<EarlyHint>\n}): EarlyHintsEvent | undefined {\n const nextHints: Array<EarlyHint> = []\n const nextLinks: Array<string> = []\n\n for (const hint of opts.hints) {\n const link = serializeEarlyHint(hint)\n if (opts.sentLinks.has(link)) continue\n opts.sentLinks.add(link)\n opts.sentHints.push(hint)\n nextHints.push(hint)\n nextLinks.push(link)\n }\n\n if (!nextHints.length && opts.phase !== 'dynamic') return undefined\n\n return {\n phase: opts.phase,\n hints: nextHints,\n links: nextLinks,\n allHints: opts.sentHints.slice(),\n allLinks: Array.from(opts.sentLinks),\n }\n}\n\nexport function createResponseLinkHeaderEntries(opts: {\n phase: EarlyHintsPhase\n hints: ReadonlyArray<EarlyHint>\n sentLinks: Set<string>\n entries: Array<ResponseLinkHeaderEntry>\n}) {\n for (const hint of opts.hints) {\n const link = serializeEarlyHint(hint)\n if (opts.sentLinks.has(link)) continue\n\n opts.sentLinks.add(link)\n opts.entries.push({ phase: opts.phase, hint, link })\n }\n}\n\nexport function getResponseLinkHeaderEntries(opts: {\n entries: ReadonlyArray<ResponseLinkHeaderEntry>\n filter?: ResponseLinkHeaderFilter\n}): Array<string> {\n if (!opts.filter) {\n return opts.entries.map((entry) => entry.link)\n }\n\n try {\n const links: Array<string> = []\n\n for (const entry of opts.entries) {\n if (opts.filter(entry)) {\n links.push(entry.link)\n }\n }\n\n return links\n } catch (err) {\n console.error('Error filtering response Link headers:', err)\n return []\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"early-hints.js","names":[],"sources":["../../src/early-hints.ts"],"sourcesContent":["import {\n getStylesheetHref,\n resolveManifestAssetLink,\n} from '@tanstack/router-core'\nimport type {\n AnyRoute,\n AnyRouteMatch,\n AssetCrossOrigin,\n Manifest,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nexport type EarlyHint = {\n href: string\n rel: 'preload' | 'modulepreload' | 'preconnect' | 'dns-prefetch'\n as?: 'fetch' | 'font' | 'image' | 'script' | 'style' | 'track'\n crossOrigin?: AssetCrossOrigin | ''\n type?: string\n integrity?: string\n referrerPolicy?: string\n fetchPriority?: string\n}\n\nexport type EarlyHintsPhase = 'static' | 'dynamic'\n\nexport type EarlyHintsEvent = {\n phase: EarlyHintsPhase\n hints: ReadonlyArray<EarlyHint>\n links: Array<string>\n allHints: ReadonlyArray<EarlyHint>\n allLinks: Array<string>\n}\n\nexport type OnEarlyHints = (event: EarlyHintsEvent) => void | Promise<void>\n\nexport type ResponseLinkHeaderEntry = {\n phase: EarlyHintsPhase\n hint: EarlyHint\n link: string\n}\n\nexport type ResponseLinkHeaderFilter = (\n entry: ResponseLinkHeaderEntry,\n) => boolean\n\nexport type ResponseLinkHeaderOptions = {\n filter?: ResponseLinkHeaderFilter\n}\n\nexport interface EarlyHintsCollector {\n collectStatic: (opts: {\n manifest: Manifest\n matchedRoutes?: ReadonlyArray<AnyRoute>\n }) => void\n collectDynamic: (matches: ReadonlyArray<AnyRouteMatch>) => void\n appendResponseHeaders: (headers: Headers) => void\n}\n\nconst LINK_PARAM_TOKEN_RE = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/\nconst PRELOAD_AS_VALUES = new Set<EarlyHint['as']>([\n 'fetch',\n 'font',\n 'image',\n 'script',\n 'style',\n 'track',\n])\n\nfunction buildLinkParam(name: string, value: string | undefined): string {\n if (value === undefined) return name\n if (LINK_PARAM_TOKEN_RE.test(value)) return `${name}=${value}`\n return `${name}=${JSON.stringify(value)}`\n}\n\nexport function serializeEarlyHint(hint: EarlyHint): string {\n const parts = [`<${hint.href}>`, buildLinkParam('rel', hint.rel)]\n if (hint.as) parts.push(buildLinkParam('as', hint.as))\n if (hint.crossOrigin !== undefined) {\n parts.push(buildLinkParam('crossorigin', hint.crossOrigin || undefined))\n }\n if (hint.type) parts.push(buildLinkParam('type', hint.type))\n if (hint.integrity) parts.push(buildLinkParam('integrity', hint.integrity))\n if (hint.referrerPolicy) {\n parts.push(buildLinkParam('referrerpolicy', hint.referrerPolicy))\n }\n if (hint.fetchPriority) {\n parts.push(buildLinkParam('fetchpriority', hint.fetchPriority))\n }\n return parts.join('; ')\n}\n\nfunction getStringAttr(\n attrs: Record<string, any> | undefined,\n name: string,\n fallbackName?: string,\n): string | undefined {\n const value =\n attrs?.[name] ?? (fallbackName ? attrs?.[fallbackName] : undefined)\n return typeof value === 'string' ? value : undefined\n}\n\nfunction getPreloadAs(\n attrs: Record<string, any> | undefined,\n): EarlyHint['as'] | undefined {\n const as = getStringAttr(attrs, 'as')\n return as && PRELOAD_AS_VALUES.has(as as EarlyHint['as'])\n ? (as as EarlyHint['as'])\n : undefined\n}\n\nfunction addEarlyHintFetchAttrs(\n hint: EarlyHint,\n attrs: Record<string, any> | undefined,\n) {\n const crossOrigin = getStringAttr(attrs, 'crossOrigin', 'crossorigin') as\n | EarlyHint['crossOrigin']\n | undefined\n const type = getStringAttr(attrs, 'type')\n const integrity = getStringAttr(attrs, 'integrity')\n const referrerPolicy = getStringAttr(\n attrs,\n 'referrerPolicy',\n 'referrerpolicy',\n )\n const fetchPriority = getStringAttr(attrs, 'fetchPriority', 'fetchpriority')\n\n if (crossOrigin !== undefined) hint.crossOrigin = crossOrigin\n if (type) hint.type = type\n if (integrity) hint.integrity = integrity\n if (referrerPolicy) hint.referrerPolicy = referrerPolicy\n if (fetchPriority) hint.fetchPriority = fetchPriority\n}\n\nfunction linkAttrsToEarlyHint(\n attrs: Record<string, any> | undefined,\n): EarlyHint | undefined {\n const href = getStringAttr(attrs, 'href')\n const rel = getStringAttr(attrs, 'rel')\n if (!href || !rel) return undefined\n\n const relTokens = rel.split(/\\s+/)\n let hintRel: EarlyHint['rel'] | undefined\n let hintAs: EarlyHint['as'] | undefined\n\n if (relTokens.includes('modulepreload')) {\n hintRel = 'modulepreload'\n hintAs = 'script'\n } else if (relTokens.includes('stylesheet')) {\n hintRel = 'preload'\n hintAs = 'style'\n } else if (relTokens.includes('preload')) {\n hintAs = getPreloadAs(attrs)\n if (!hintAs) return undefined\n hintRel = 'preload'\n } else if (relTokens.includes('preconnect')) {\n hintRel = 'preconnect'\n hintAs = undefined\n } else if (relTokens.includes('dns-prefetch')) {\n hintRel = 'dns-prefetch'\n hintAs = undefined\n }\n\n if (!hintRel) return undefined\n\n const hint: EarlyHint = {\n href,\n rel: hintRel,\n }\n\n if (hintAs) hint.as = hintAs\n addEarlyHintFetchAttrs(hint, attrs)\n\n return hint\n}\n\nexport function collectStaticHintsFromManifest(\n manifest: Manifest,\n matchedRoutes: ReadonlyArray<AnyRoute>,\n): Array<EarlyHint> {\n const hints: Array<EarlyHint> = []\n\n for (const route of matchedRoutes) {\n const routeManifest = manifest.routes[route.id]\n if (!routeManifest) continue\n\n for (const link of routeManifest.preloads ?? []) {\n const { href, crossOrigin } = resolveManifestAssetLink(link)\n const hint: EarlyHint = { href, rel: 'modulepreload', as: 'script' }\n if (crossOrigin !== undefined) hint.crossOrigin = crossOrigin\n hints.push(hint)\n }\n\n for (const asset of routeManifest.assets ?? []) {\n if (asset.tag !== 'link') continue\n\n const stylesheetHref = getStylesheetHref(asset)\n if (stylesheetHref) {\n if (manifest.inlineCss?.styles[stylesheetHref] !== undefined) continue\n\n const hint: EarlyHint = {\n href: stylesheetHref,\n rel: 'preload',\n as: 'style',\n }\n addEarlyHintFetchAttrs(hint, asset.attrs)\n hints.push(hint)\n continue\n }\n\n const hint = linkAttrsToEarlyHint(asset.attrs)\n if (hint) {\n hints.push(hint)\n }\n }\n }\n\n return hints\n}\n\nexport function collectDynamicHintsFromMatches(\n matches: ReadonlyArray<AnyRouteMatch>,\n): Array<EarlyHint> {\n const hints: Array<EarlyHint> = []\n\n for (const match of matches) {\n const links = match.links\n if (!Array.isArray(links)) continue\n\n for (const link of links as Array<RouterManagedTag['attrs']>) {\n const hint = linkAttrsToEarlyHint(link)\n if (hint) hints.push(hint)\n }\n }\n\n return hints\n}\n\nexport function createEarlyHintsEvent(opts: {\n phase: EarlyHintsPhase\n hints: ReadonlyArray<EarlyHint>\n sentLinks: Set<string>\n sentHints: Array<EarlyHint>\n}): EarlyHintsEvent | undefined {\n const nextHints: Array<EarlyHint> = []\n const nextLinks: Array<string> = []\n\n for (const hint of opts.hints) {\n const link = serializeEarlyHint(hint)\n if (opts.sentLinks.has(link)) continue\n opts.sentLinks.add(link)\n opts.sentHints.push(hint)\n nextHints.push(hint)\n nextLinks.push(link)\n }\n\n if (!nextHints.length && opts.phase !== 'dynamic') return undefined\n\n return {\n phase: opts.phase,\n hints: nextHints,\n links: nextLinks,\n allHints: opts.sentHints.slice(),\n allLinks: Array.from(opts.sentLinks),\n }\n}\n\nexport function createResponseLinkHeaderEntries(opts: {\n phase: EarlyHintsPhase\n hints: ReadonlyArray<EarlyHint>\n sentLinks: Set<string>\n entries: Array<ResponseLinkHeaderEntry>\n}) {\n for (const hint of opts.hints) {\n const link = serializeEarlyHint(hint)\n if (opts.sentLinks.has(link)) continue\n\n opts.sentLinks.add(link)\n opts.entries.push({ phase: opts.phase, hint, link })\n }\n}\n\nexport function getResponseLinkHeaderEntries(opts: {\n entries: ReadonlyArray<ResponseLinkHeaderEntry>\n filter?: ResponseLinkHeaderFilter\n}): Array<string> {\n if (!opts.filter) {\n return opts.entries.map((entry) => entry.link)\n }\n\n try {\n const links: Array<string> = []\n\n for (const entry of opts.entries) {\n if (opts.filter(entry)) {\n links.push(entry.link)\n }\n }\n\n return links\n } catch (err) {\n console.error('Error filtering response Link headers:', err)\n return []\n }\n}\n\nfunction notifyEarlyHints(\n phase: EarlyHintsPhase,\n event: EarlyHintsEvent,\n onEarlyHints: OnEarlyHints,\n) {\n try {\n const result = onEarlyHints(event)\n if (result) {\n void Promise.resolve(result).catch((err) => {\n console.error(`Error sending ${phase} early hints:`, err)\n })\n }\n } catch (err) {\n console.error(`Error sending ${phase} early hints:`, err)\n }\n}\n\nfunction getResponseLinkHeaderFilter(\n responseLinkHeader: boolean | ResponseLinkHeaderOptions | undefined,\n): ResponseLinkHeaderFilter | undefined {\n if (typeof responseLinkHeader !== 'object') {\n return undefined\n }\n\n return responseLinkHeader.filter\n}\n\nfunction appendResponseLinkHeaders(opts: {\n responseHeaders: Headers\n entries: ReadonlyArray<ResponseLinkHeaderEntry>\n filter?: ResponseLinkHeaderFilter\n}) {\n for (const link of getResponseLinkHeaderEntries(opts)) {\n opts.responseHeaders.append('Link', link)\n }\n}\n\nfunction collectResponseLinkHeaderEntries(opts: {\n phase: EarlyHintsPhase\n event: EarlyHintsEvent\n entries: Array<ResponseLinkHeaderEntry>\n}) {\n for (let index = 0; index < opts.event.hints.length; index++) {\n opts.entries.push({\n phase: opts.phase,\n hint: opts.event.hints[index]!,\n link: opts.event.links[index]!,\n })\n }\n}\n\nfunction collectEarlyHintsPhase(opts: {\n phase: EarlyHintsPhase\n hints: ReadonlyArray<EarlyHint>\n sentLinks: Set<string>\n sentHints?: Array<EarlyHint>\n onEarlyHints?: OnEarlyHints\n responseLinkHeaderEntries?: Array<ResponseLinkHeaderEntry>\n}) {\n const event = opts.onEarlyHints\n ? createEarlyHintsEvent({\n phase: opts.phase,\n hints: opts.hints,\n sentLinks: opts.sentLinks,\n sentHints: opts.sentHints!,\n })\n : undefined\n\n if (event) {\n notifyEarlyHints(opts.phase, event, opts.onEarlyHints!)\n }\n\n if (!opts.responseLinkHeaderEntries) return\n\n if (event) {\n collectResponseLinkHeaderEntries({\n phase: opts.phase,\n event,\n entries: opts.responseLinkHeaderEntries,\n })\n return\n }\n\n createResponseLinkHeaderEntries({\n phase: opts.phase,\n hints: opts.hints,\n sentLinks: opts.sentLinks,\n entries: opts.responseLinkHeaderEntries,\n })\n}\n\nexport function createEarlyHintsCollector(\n opts:\n | {\n onEarlyHints?: OnEarlyHints\n responseLinkHeader?: boolean | ResponseLinkHeaderOptions\n }\n | undefined,\n): EarlyHintsCollector | undefined {\n if (\n process.env.TSS_DEV_SERVER === 'true' ||\n (!opts?.onEarlyHints && !opts?.responseLinkHeader)\n ) {\n return undefined\n }\n\n const sentLinks = new Set<string>()\n const sentHints = opts.onEarlyHints ? new Array<EarlyHint>() : undefined\n const responseLinkHeaderEntries = opts.responseLinkHeader\n ? new Array<ResponseLinkHeaderEntry>()\n : undefined\n const responseLinkHeaderFilter = getResponseLinkHeaderFilter(\n opts.responseLinkHeader,\n )\n\n return {\n collectStatic: ({ manifest, matchedRoutes }) => {\n if (!matchedRoutes?.length) return\n\n collectEarlyHintsPhase({\n phase: 'static',\n hints: collectStaticHintsFromManifest(manifest, matchedRoutes),\n sentLinks,\n sentHints,\n onEarlyHints: opts.onEarlyHints,\n responseLinkHeaderEntries,\n })\n },\n collectDynamic: (matches) => {\n collectEarlyHintsPhase({\n phase: 'dynamic',\n hints: collectDynamicHintsFromMatches(matches),\n sentLinks,\n sentHints,\n onEarlyHints: opts.onEarlyHints,\n responseLinkHeaderEntries,\n })\n },\n appendResponseHeaders: (headers) => {\n if (!responseLinkHeaderEntries?.length) return\n\n appendResponseLinkHeaders({\n responseHeaders: headers,\n entries: responseLinkHeaderEntries,\n filter: responseLinkHeaderFilter,\n })\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Manifest } from '@tanstack/router-core';
|
|
2
|
+
import { HandlerInlineCssOption } from './inlineCss.js';
|
|
3
|
+
import { StartManifestWithClientEntry, TransformAssets } from './transformAssetUrls.js';
|
|
4
|
+
export type { HandlerInlineCssOption, StartManifestWithClientEntry, TransformAssets, };
|
|
5
|
+
export interface FinalManifestOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Controls whether Start inlines build-collected CSS by default at runtime.
|
|
8
|
+
*
|
|
9
|
+
* This only has an effect when the build was created with
|
|
10
|
+
* `server.build.inlineCss` enabled. Pass a callback to decide per request.
|
|
11
|
+
* `handler(request, { inlineCss })` overrides this value for that request.
|
|
12
|
+
*
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
inlineCss?: HandlerInlineCssOption;
|
|
16
|
+
/**
|
|
17
|
+
* Transform manifest-managed asset URLs and attributes at runtime, e.g. to
|
|
18
|
+
* prepend a CDN prefix.
|
|
19
|
+
*
|
|
20
|
+
* This covers JS preloads, CSS links, the client entry script, and URLs
|
|
21
|
+
* inside build-collected inline CSS. Asset imports used directly in
|
|
22
|
+
* components should be handled by the bundler instead.
|
|
23
|
+
*/
|
|
24
|
+
transformAssets?: TransformAssets;
|
|
25
|
+
}
|
|
26
|
+
export type GetBaseManifest = () => Promise<StartManifestWithClientEntry>;
|
|
27
|
+
export interface FinalManifestRequestOptions {
|
|
28
|
+
request: Request;
|
|
29
|
+
requestInlineCss: boolean | undefined;
|
|
30
|
+
getBaseManifest: GetBaseManifest;
|
|
31
|
+
}
|
|
32
|
+
export interface FinalManifestResolver {
|
|
33
|
+
warmup: (opts: {
|
|
34
|
+
getBaseManifest: GetBaseManifest;
|
|
35
|
+
}) => Promise<Manifest> | undefined;
|
|
36
|
+
resolveCached: (opts: FinalManifestRequestOptions) => Promise<Manifest>;
|
|
37
|
+
resolveUncached: (opts: FinalManifestRequestOptions) => Promise<Manifest>;
|
|
38
|
+
}
|
|
39
|
+
export declare function createCachedBaseManifestLoader(loadBaseManifest: GetBaseManifest): GetBaseManifest;
|
|
40
|
+
export declare function createFinalManifestResolver(opts: FinalManifestOptions & {
|
|
41
|
+
cacheCreateTransform: boolean;
|
|
42
|
+
}): FinalManifestResolver;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { buildManifestWithClientEntry, resolveTransformAssetsConfig, transformManifestAssets } from "./transformAssetUrls.js";
|
|
2
|
+
import { getStaticHandlerInlineCssDefault, resolveInlineCssForRequest } from "./inlineCss.js";
|
|
3
|
+
//#region src/finalManifest.ts
|
|
4
|
+
function createCachedBaseManifestLoader(loadBaseManifest) {
|
|
5
|
+
let baseManifestPromise;
|
|
6
|
+
return () => {
|
|
7
|
+
if (!baseManifestPromise) baseManifestPromise = loadBaseManifest().catch((error) => {
|
|
8
|
+
baseManifestPromise = void 0;
|
|
9
|
+
throw error;
|
|
10
|
+
});
|
|
11
|
+
return baseManifestPromise;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function createFinalManifestTransformResolver(transformAssets, opts) {
|
|
15
|
+
const transformConfig = transformAssets !== void 0 ? resolveTransformAssetsConfig(transformAssets) : void 0;
|
|
16
|
+
const cache = transformConfig ? transformConfig.cache : true;
|
|
17
|
+
const warmup = !!transformAssets && typeof transformAssets === "object" && "warmup" in transformAssets && transformAssets.warmup === true;
|
|
18
|
+
let cachedCreateTransformPromise;
|
|
19
|
+
const clearCachedCreateTransform = () => {
|
|
20
|
+
cachedCreateTransformPromise = void 0;
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
cache,
|
|
24
|
+
warmup,
|
|
25
|
+
clearCachedCreateTransform,
|
|
26
|
+
getTransformFn: async (ctx) => {
|
|
27
|
+
if (!transformConfig) return void 0;
|
|
28
|
+
if (transformConfig.type !== "createTransform") return transformConfig.transformFn;
|
|
29
|
+
if (!cache || !opts.cacheCreateTransform) return transformConfig.createTransform(ctx);
|
|
30
|
+
if (!cachedCreateTransformPromise) cachedCreateTransformPromise = Promise.resolve(transformConfig.createTransform(ctx)).catch((error) => {
|
|
31
|
+
clearCachedCreateTransform();
|
|
32
|
+
throw error;
|
|
33
|
+
});
|
|
34
|
+
return cachedCreateTransformPromise;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function createFinalManifestResolver(opts) {
|
|
39
|
+
const finalManifestCache = /* @__PURE__ */ new Map();
|
|
40
|
+
const transformResolver = createFinalManifestTransformResolver(opts.transformAssets, { cacheCreateTransform: opts.cacheCreateTransform });
|
|
41
|
+
const handlerDefaultInlineCss = getStaticHandlerInlineCssDefault(opts.inlineCss);
|
|
42
|
+
const getRequestManifestOptions = async (requestOpts) => {
|
|
43
|
+
const transformFn = await transformResolver.getTransformFn({
|
|
44
|
+
warmup: false,
|
|
45
|
+
request: requestOpts.request
|
|
46
|
+
});
|
|
47
|
+
const inlineCss = await resolveInlineCssForRequest({
|
|
48
|
+
request: requestOpts.request,
|
|
49
|
+
handlerInlineCss: opts.inlineCss,
|
|
50
|
+
requestInlineCss: requestOpts.requestInlineCss
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
getBaseManifest: requestOpts.getBaseManifest,
|
|
54
|
+
transformFn,
|
|
55
|
+
cache: transformResolver.cache,
|
|
56
|
+
inlineCss
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
const resolveRequest = async (requestOpts, cache) => {
|
|
60
|
+
return resolveFinalManifest({
|
|
61
|
+
...await getRequestManifestOptions(requestOpts),
|
|
62
|
+
finalManifestCache: cache
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
warmup: ({ getBaseManifest }) => warmupFinalManifest({
|
|
67
|
+
enabled: transformResolver.warmup,
|
|
68
|
+
handlerDefaultInlineCss,
|
|
69
|
+
cache: transformResolver.cache,
|
|
70
|
+
finalManifestCache,
|
|
71
|
+
getBaseManifest,
|
|
72
|
+
getTransformFn: () => transformResolver.getTransformFn({ warmup: true }),
|
|
73
|
+
onError: transformResolver.clearCachedCreateTransform
|
|
74
|
+
}),
|
|
75
|
+
resolveCached: (requestOpts) => resolveRequest(requestOpts, finalManifestCache),
|
|
76
|
+
resolveUncached: (requestOpts) => resolveRequest(requestOpts, void 0)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function getFinalManifestCacheKey(inlineCss) {
|
|
80
|
+
return inlineCss ? "inline-css" : "linked-css";
|
|
81
|
+
}
|
|
82
|
+
function cacheFinalManifestPromise(cachedFinalManifestPromises, cacheKey, promise) {
|
|
83
|
+
const cachedFinalManifestPromise = promise.catch((error) => {
|
|
84
|
+
if (cachedFinalManifestPromises.get(cacheKey) === cachedFinalManifestPromise) cachedFinalManifestPromises.delete(cacheKey);
|
|
85
|
+
throw error;
|
|
86
|
+
});
|
|
87
|
+
cachedFinalManifestPromises.set(cacheKey, cachedFinalManifestPromise);
|
|
88
|
+
return cachedFinalManifestPromise;
|
|
89
|
+
}
|
|
90
|
+
function getOrCreateCachedFinalManifestPromise(cachedFinalManifestPromises, cacheKey, computeFinalManifest) {
|
|
91
|
+
const cachedFinalManifestPromise = cachedFinalManifestPromises.get(cacheKey);
|
|
92
|
+
if (cachedFinalManifestPromise) return cachedFinalManifestPromise;
|
|
93
|
+
return cacheFinalManifestPromise(cachedFinalManifestPromises, cacheKey, Promise.resolve().then(computeFinalManifest));
|
|
94
|
+
}
|
|
95
|
+
async function buildFinalManifest(opts) {
|
|
96
|
+
return opts.transformFn ? await transformManifestAssets(opts.base, opts.transformFn, { inlineCss: opts.inlineCss }) : buildManifestWithClientEntry(opts.base, { inlineCss: opts.inlineCss });
|
|
97
|
+
}
|
|
98
|
+
async function resolveFinalManifest(opts) {
|
|
99
|
+
const computeFinalManifest = async () => {
|
|
100
|
+
return buildFinalManifest({
|
|
101
|
+
base: await opts.getBaseManifest(),
|
|
102
|
+
transformFn: opts.transformFn,
|
|
103
|
+
inlineCss: opts.inlineCss
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
if (opts.finalManifestCache && (!opts.transformFn || opts.cache)) return getOrCreateCachedFinalManifestPromise(opts.finalManifestCache, getFinalManifestCacheKey(opts.inlineCss), computeFinalManifest);
|
|
107
|
+
return computeFinalManifest();
|
|
108
|
+
}
|
|
109
|
+
function warmupFinalManifest(opts) {
|
|
110
|
+
if (!opts.enabled || opts.handlerDefaultInlineCss === void 0 || !opts.cache) return;
|
|
111
|
+
const inlineCss = opts.handlerDefaultInlineCss;
|
|
112
|
+
const warmupPromise = getOrCreateCachedFinalManifestPromise(opts.finalManifestCache, getFinalManifestCacheKey(inlineCss), async () => {
|
|
113
|
+
const [base, transformFn] = await Promise.all([opts.getBaseManifest(), opts.getTransformFn()]);
|
|
114
|
+
return buildFinalManifest({
|
|
115
|
+
base,
|
|
116
|
+
transformFn,
|
|
117
|
+
inlineCss
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
if (opts.onError) warmupPromise.catch(opts.onError);
|
|
121
|
+
return warmupPromise;
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
export { createCachedBaseManifestLoader, createFinalManifestResolver };
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=finalManifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finalManifest.js","names":[],"sources":["../../src/finalManifest.ts"],"sourcesContent":["import {\n buildManifestWithClientEntry,\n resolveTransformAssetsConfig,\n transformManifestAssets,\n} from './transformAssetUrls'\nimport {\n getStaticHandlerInlineCssDefault,\n resolveInlineCssForRequest,\n} from './inlineCss'\nimport type { Manifest } from '@tanstack/router-core'\nimport type { HandlerInlineCssOption } from './inlineCss'\nimport type {\n CreateTransformAssetsContext,\n StartManifestWithClientEntry,\n TransformAssets,\n TransformAssetsFn,\n} from './transformAssetUrls'\n\nexport type {\n HandlerInlineCssOption,\n StartManifestWithClientEntry,\n TransformAssets,\n}\n\nexport interface FinalManifestOptions {\n /**\n * Controls whether Start inlines build-collected CSS by default at runtime.\n *\n * This only has an effect when the build was created with\n * `server.build.inlineCss` enabled. Pass a callback to decide per request.\n * `handler(request, { inlineCss })` overrides this value for that request.\n *\n * @default true\n */\n inlineCss?: HandlerInlineCssOption\n /**\n * Transform manifest-managed asset URLs and attributes at runtime, e.g. to\n * prepend a CDN prefix.\n *\n * This covers JS preloads, CSS links, the client entry script, and URLs\n * inside build-collected inline CSS. Asset imports used directly in\n * components should be handled by the bundler instead.\n */\n transformAssets?: TransformAssets\n}\n\ntype FinalManifestCacheKey = 'inline-css' | 'linked-css'\ntype FinalManifestCache = Map<FinalManifestCacheKey, Promise<Manifest>>\nexport type GetBaseManifest = () => Promise<StartManifestWithClientEntry>\n\nexport interface FinalManifestRequestOptions {\n request: Request\n requestInlineCss: boolean | undefined\n getBaseManifest: GetBaseManifest\n}\n\ninterface FinalManifestTransformResolver {\n cache: boolean\n warmup: boolean\n getTransformFn: (\n ctx: CreateTransformAssetsContext,\n ) => Promise<TransformAssetsFn | undefined>\n clearCachedCreateTransform: () => void\n}\n\nexport interface FinalManifestResolver {\n warmup: (opts: {\n getBaseManifest: GetBaseManifest\n }) => Promise<Manifest> | undefined\n resolveCached: (opts: FinalManifestRequestOptions) => Promise<Manifest>\n resolveUncached: (opts: FinalManifestRequestOptions) => Promise<Manifest>\n}\n\nexport function createCachedBaseManifestLoader(\n loadBaseManifest: GetBaseManifest,\n): GetBaseManifest {\n let baseManifestPromise: Promise<StartManifestWithClientEntry> | undefined\n\n return () => {\n if (!baseManifestPromise) {\n baseManifestPromise = loadBaseManifest().catch((error) => {\n baseManifestPromise = undefined\n throw error\n })\n }\n\n return baseManifestPromise\n }\n}\n\nfunction createFinalManifestTransformResolver(\n transformAssets: TransformAssets | undefined,\n opts: { cacheCreateTransform: boolean },\n): FinalManifestTransformResolver {\n const transformConfig =\n transformAssets !== undefined\n ? resolveTransformAssetsConfig(transformAssets)\n : undefined\n const cache = transformConfig ? transformConfig.cache : true\n const warmup =\n !!transformAssets &&\n typeof transformAssets === 'object' &&\n 'warmup' in transformAssets &&\n transformAssets.warmup === true\n\n let cachedCreateTransformPromise: Promise<TransformAssetsFn> | undefined\n\n const clearCachedCreateTransform = () => {\n cachedCreateTransformPromise = undefined\n }\n\n return {\n cache,\n warmup,\n clearCachedCreateTransform,\n getTransformFn: async (ctx) => {\n if (!transformConfig) return undefined\n\n if (transformConfig.type !== 'createTransform') {\n return transformConfig.transformFn\n }\n\n if (!cache || !opts.cacheCreateTransform) {\n return transformConfig.createTransform(ctx)\n }\n\n if (!cachedCreateTransformPromise) {\n cachedCreateTransformPromise = Promise.resolve(\n transformConfig.createTransform(ctx),\n ).catch((error) => {\n clearCachedCreateTransform()\n throw error\n })\n }\n\n return cachedCreateTransformPromise\n },\n }\n}\n\nexport function createFinalManifestResolver(\n opts: FinalManifestOptions & { cacheCreateTransform: boolean },\n): FinalManifestResolver {\n const finalManifestCache: FinalManifestCache = new Map()\n const transformResolver = createFinalManifestTransformResolver(\n opts.transformAssets,\n { cacheCreateTransform: opts.cacheCreateTransform },\n )\n const handlerDefaultInlineCss = getStaticHandlerInlineCssDefault(\n opts.inlineCss,\n )\n\n const getRequestManifestOptions = async (\n requestOpts: FinalManifestRequestOptions,\n ) => {\n const transformFn = await transformResolver.getTransformFn({\n warmup: false,\n request: requestOpts.request,\n })\n const inlineCss = await resolveInlineCssForRequest({\n request: requestOpts.request,\n handlerInlineCss: opts.inlineCss,\n requestInlineCss: requestOpts.requestInlineCss,\n })\n\n return {\n getBaseManifest: requestOpts.getBaseManifest,\n transformFn,\n cache: transformResolver.cache,\n inlineCss,\n }\n }\n\n const resolveRequest = async (\n requestOpts: FinalManifestRequestOptions,\n cache: FinalManifestCache | undefined,\n ) => {\n return resolveFinalManifest({\n ...(await getRequestManifestOptions(requestOpts)),\n finalManifestCache: cache,\n })\n }\n\n return {\n warmup: ({ getBaseManifest }) =>\n warmupFinalManifest({\n enabled: transformResolver.warmup,\n handlerDefaultInlineCss,\n cache: transformResolver.cache,\n finalManifestCache,\n getBaseManifest,\n getTransformFn: () =>\n transformResolver.getTransformFn({ warmup: true }),\n onError: transformResolver.clearCachedCreateTransform,\n }),\n resolveCached: (requestOpts) =>\n resolveRequest(requestOpts, finalManifestCache),\n resolveUncached: (requestOpts) => resolveRequest(requestOpts, undefined),\n }\n}\n\nfunction getFinalManifestCacheKey(inlineCss: boolean): FinalManifestCacheKey {\n return inlineCss ? 'inline-css' : 'linked-css'\n}\n\nfunction cacheFinalManifestPromise(\n cachedFinalManifestPromises: FinalManifestCache,\n cacheKey: FinalManifestCacheKey,\n promise: Promise<Manifest>,\n): Promise<Manifest> {\n const cachedFinalManifestPromise = promise.catch((error) => {\n if (\n cachedFinalManifestPromises.get(cacheKey) === cachedFinalManifestPromise\n ) {\n cachedFinalManifestPromises.delete(cacheKey)\n }\n throw error\n })\n\n cachedFinalManifestPromises.set(cacheKey, cachedFinalManifestPromise)\n return cachedFinalManifestPromise\n}\n\nfunction getOrCreateCachedFinalManifestPromise(\n cachedFinalManifestPromises: FinalManifestCache,\n cacheKey: FinalManifestCacheKey,\n computeFinalManifest: () => Promise<Manifest>,\n): Promise<Manifest> {\n const cachedFinalManifestPromise = cachedFinalManifestPromises.get(cacheKey)\n if (cachedFinalManifestPromise) {\n return cachedFinalManifestPromise\n }\n\n return cacheFinalManifestPromise(\n cachedFinalManifestPromises,\n cacheKey,\n Promise.resolve().then(computeFinalManifest),\n )\n}\n\nasync function buildFinalManifest(opts: {\n base: StartManifestWithClientEntry\n transformFn: TransformAssetsFn | undefined\n inlineCss: boolean\n}): Promise<Manifest> {\n return opts.transformFn\n ? await transformManifestAssets(opts.base, opts.transformFn, {\n inlineCss: opts.inlineCss,\n })\n : buildManifestWithClientEntry(opts.base, { inlineCss: opts.inlineCss })\n}\n\nasync function resolveFinalManifest(opts: {\n getBaseManifest: () => Promise<StartManifestWithClientEntry>\n transformFn: TransformAssetsFn | undefined\n cache: boolean\n inlineCss: boolean\n finalManifestCache?: FinalManifestCache\n}): Promise<Manifest> {\n const computeFinalManifest = async () => {\n return buildFinalManifest({\n base: await opts.getBaseManifest(),\n transformFn: opts.transformFn,\n inlineCss: opts.inlineCss,\n })\n }\n\n if (opts.finalManifestCache && (!opts.transformFn || opts.cache)) {\n return getOrCreateCachedFinalManifestPromise(\n opts.finalManifestCache,\n getFinalManifestCacheKey(opts.inlineCss),\n computeFinalManifest,\n )\n }\n\n return computeFinalManifest()\n}\n\nfunction warmupFinalManifest(opts: {\n enabled: boolean\n handlerDefaultInlineCss: boolean | undefined\n cache: boolean\n finalManifestCache: FinalManifestCache\n getBaseManifest: () => Promise<StartManifestWithClientEntry>\n getTransformFn: () => Promise<TransformAssetsFn | undefined>\n onError?: () => void\n}): Promise<Manifest> | undefined {\n if (\n !opts.enabled ||\n opts.handlerDefaultInlineCss === undefined ||\n !opts.cache\n ) {\n return undefined\n }\n\n const inlineCss = opts.handlerDefaultInlineCss\n const warmupPromise = getOrCreateCachedFinalManifestPromise(\n opts.finalManifestCache,\n getFinalManifestCacheKey(inlineCss),\n async () => {\n const [base, transformFn] = await Promise.all([\n opts.getBaseManifest(),\n opts.getTransformFn(),\n ])\n\n return buildFinalManifest({\n base,\n transformFn,\n inlineCss,\n })\n },\n )\n\n if (opts.onError) {\n void warmupPromise.catch(opts.onError)\n }\n\n return warmupPromise\n}\n"],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { createStartHandler } from './createStartHandler.js';
|
|
2
2
|
export type { CreateStartHandlerOptions } from './createStartHandler.js';
|
|
3
|
-
export type { TransformAssets, TransformAssetsFn, TransformAssetsContext, TransformAssetsOptions, TransformAssetsObjectShorthand, TransformAssetsCrossOriginConfig, TransformAssetResult,
|
|
3
|
+
export type { TransformAssets, TransformAssetsFn, TransformAssetsContext, TransformAssetsOptions, TransformAssetsObjectShorthand, TransformAssetsCrossOriginConfig, TransformAssetResult, TransformAssetKind, CreateTransformAssetsContext, } from './transformAssetUrls.js';
|
|
4
4
|
export { attachRouterServerSsrUtils, createRequestHandler, defineHandlerCallback, transformReadableStreamWithRouter, transformPipeableStreamWithRouter, } from '@tanstack/router-core/ssr/server';
|
|
5
5
|
export type { HandlerCallback } from '@tanstack/router-core/ssr/server';
|
|
6
6
|
export * from './request-response.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Awaitable } from '@tanstack/router-core';
|
|
2
|
+
export type HandlerInlineCssOption = boolean | ((ctx: {
|
|
3
|
+
request: Request;
|
|
4
|
+
}) => Awaitable<boolean>);
|
|
5
|
+
export declare function getStaticHandlerInlineCssDefault(handlerInlineCss: HandlerInlineCssOption | undefined): boolean | undefined;
|
|
6
|
+
export declare function resolveInlineCssForRequest(opts: {
|
|
7
|
+
request: Request;
|
|
8
|
+
handlerInlineCss: HandlerInlineCssOption | undefined;
|
|
9
|
+
requestInlineCss: boolean | undefined;
|
|
10
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/inlineCss.ts
|
|
2
|
+
function getStaticHandlerInlineCssDefault(handlerInlineCss) {
|
|
3
|
+
if (typeof handlerInlineCss === "function") return;
|
|
4
|
+
return handlerInlineCss ?? true;
|
|
5
|
+
}
|
|
6
|
+
async function resolveInlineCssForRequest(opts) {
|
|
7
|
+
if (opts.requestInlineCss !== void 0) return opts.requestInlineCss;
|
|
8
|
+
if (typeof opts.handlerInlineCss === "function") return await opts.handlerInlineCss({ request: opts.request });
|
|
9
|
+
return opts.handlerInlineCss ?? true;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { getStaticHandlerInlineCssDefault, resolveInlineCssForRequest };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=inlineCss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inlineCss.js","names":[],"sources":["../../src/inlineCss.ts"],"sourcesContent":["import type { Awaitable } from '@tanstack/router-core'\n\nexport type HandlerInlineCssOption =\n | boolean\n | ((ctx: { request: Request }) => Awaitable<boolean>)\n\nexport function getStaticHandlerInlineCssDefault(\n handlerInlineCss: HandlerInlineCssOption | undefined,\n) {\n if (typeof handlerInlineCss === 'function') {\n return undefined\n }\n\n return handlerInlineCss ?? true\n}\n\nexport async function resolveInlineCssForRequest(opts: {\n request: Request\n handlerInlineCss: HandlerInlineCssOption | undefined\n requestInlineCss: boolean | undefined\n}) {\n if (opts.requestInlineCss !== undefined) {\n return opts.requestInlineCss\n }\n\n if (typeof opts.handlerInlineCss === 'function') {\n return await opts.handlerInlineCss({ request: opts.request })\n }\n\n return opts.handlerInlineCss ?? true\n}\n"],"mappings":";AAMA,SAAgB,iCACd,kBACA;AACA,KAAI,OAAO,qBAAqB,WAC9B;AAGF,QAAO,oBAAoB;;AAG7B,eAAsB,2BAA2B,MAI9C;AACD,KAAI,KAAK,qBAAqB,KAAA,EAC5B,QAAO,KAAK;AAGd,KAAI,OAAO,KAAK,qBAAqB,WACnC,QAAO,MAAM,KAAK,iBAAiB,EAAE,SAAS,KAAK,SAAS,CAAC;AAG/D,QAAO,KAAK,oBAAoB"}
|
|
@@ -42,7 +42,17 @@ type EarlyHintsOptions = {
|
|
|
42
42
|
*/
|
|
43
43
|
responseLinkHeader?: boolean | ResponseLinkHeaderOptions;
|
|
44
44
|
};
|
|
45
|
-
|
|
45
|
+
type InlineCssOptions = {
|
|
46
|
+
/**
|
|
47
|
+
* Controls whether Start inlines build-collected CSS for this request.
|
|
48
|
+
*
|
|
49
|
+
* This only has an effect when the build was created with
|
|
50
|
+
* `server.build.inlineCss` enabled. Defaults to `true` so builds with inline
|
|
51
|
+
* CSS enabled continue to inline CSS unless a request opts out.
|
|
52
|
+
*/
|
|
53
|
+
inlineCss?: boolean;
|
|
54
|
+
};
|
|
55
|
+
export type RequestOptions<TRegister> = EarlyHintsOptions & InlineCssOptions & (TRegister extends {
|
|
46
56
|
server: {
|
|
47
57
|
requestContext: infer TRequestContext;
|
|
48
58
|
};
|
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import { AssetCrossOrigin, Awaitable, Manifest, RouterManagedTag } from '@tanstack/router-core';
|
|
2
2
|
export type { AssetCrossOrigin };
|
|
3
|
-
export type
|
|
4
|
-
type TransformAssetsShorthandCrossOriginKind = Exclude<TransformAssetKind, 'clientEntry'>;
|
|
5
|
-
export type AssetUrlType = TransformAssetKind;
|
|
6
|
-
export interface TransformAssetsContext {
|
|
3
|
+
export type TransformAssetsContext = {
|
|
7
4
|
url: string;
|
|
8
|
-
kind:
|
|
9
|
-
}
|
|
5
|
+
kind: 'modulepreload';
|
|
6
|
+
} | {
|
|
7
|
+
url: string;
|
|
8
|
+
kind: 'stylesheet';
|
|
9
|
+
} | {
|
|
10
|
+
url: string;
|
|
11
|
+
kind: 'clientEntry';
|
|
12
|
+
} | {
|
|
13
|
+
url: string;
|
|
14
|
+
kind: 'css-url';
|
|
15
|
+
stylesheetHref: string;
|
|
16
|
+
};
|
|
17
|
+
export type TransformAssetKind = TransformAssetsContext['kind'];
|
|
18
|
+
type TransformAssetsShorthandCrossOriginKind = Exclude<TransformAssetKind, 'clientEntry' | 'css-url'>;
|
|
10
19
|
export type TransformAssetResult = string | {
|
|
11
20
|
href: string;
|
|
12
21
|
crossOrigin?: AssetCrossOrigin;
|
|
13
22
|
};
|
|
14
23
|
export type TransformAssetsFn = (context: TransformAssetsContext) => Awaitable<TransformAssetResult>;
|
|
15
|
-
export
|
|
16
|
-
url: string;
|
|
17
|
-
type: AssetUrlType;
|
|
18
|
-
}
|
|
19
|
-
export type TransformAssetUrlsFn = (context: TransformAssetUrlsContext) => Awaitable<string>;
|
|
20
|
-
export type CreateTransformAssetUrlsContext = {
|
|
24
|
+
export type CreateTransformAssetsContext = {
|
|
21
25
|
/** True when the server is computing the cached manifest during startup warmup. */
|
|
22
26
|
warmup: true;
|
|
23
27
|
} | {
|
|
@@ -30,13 +34,8 @@ export type CreateTransformAssetUrlsContext = {
|
|
|
30
34
|
/** False when transforming URLs as part of request handling. */
|
|
31
35
|
warmup: false;
|
|
32
36
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* per-asset transform.
|
|
36
|
-
*/
|
|
37
|
-
export type CreateTransformAssetUrlsFn = (ctx: CreateTransformAssetUrlsContext) => Awaitable<TransformAssetUrlsFn>;
|
|
38
|
-
export type CreateTransformAssetsFn = (ctx: CreateTransformAssetUrlsContext) => Awaitable<TransformAssetsFn>;
|
|
39
|
-
type TransformAssetUrlsOptionsBase = {
|
|
37
|
+
export type CreateTransformAssetsFn = (ctx: CreateTransformAssetsContext) => Awaitable<TransformAssetsFn>;
|
|
38
|
+
type TransformAssetsOptionsBase = {
|
|
40
39
|
/**
|
|
41
40
|
* Whether to cache the transformed manifest after the first request.
|
|
42
41
|
*
|
|
@@ -60,35 +59,13 @@ type TransformAssetUrlsOptionsBase = {
|
|
|
60
59
|
*/
|
|
61
60
|
warmup?: boolean;
|
|
62
61
|
};
|
|
63
|
-
export type
|
|
64
|
-
/**
|
|
65
|
-
* The transform to apply to asset URLs. Can be a string prefix or a callback.
|
|
66
|
-
*
|
|
67
|
-
* **String** — prepended to every asset URL.
|
|
68
|
-
* **Callback** — receives `{ url, type }` and returns a new URL.
|
|
69
|
-
*/
|
|
70
|
-
transform: string | TransformAssetUrlsFn;
|
|
71
|
-
createTransform?: never;
|
|
72
|
-
}) | (TransformAssetUrlsOptionsBase & {
|
|
73
|
-
/**
|
|
74
|
-
* Create a per-asset transform function.
|
|
75
|
-
*
|
|
76
|
-
* This factory runs once per manifest computation (per request when
|
|
77
|
-
* `cache: false`, or once per server when `cache: true`). It can do async
|
|
78
|
-
* setup work (fetch config, read from a KV, etc.) and return a fast
|
|
79
|
-
* per-asset transformer.
|
|
80
|
-
*/
|
|
81
|
-
createTransform: CreateTransformAssetUrlsFn;
|
|
82
|
-
transform?: never;
|
|
83
|
-
});
|
|
84
|
-
export type TransformAssetsOptions = (TransformAssetUrlsOptionsBase & {
|
|
62
|
+
export type TransformAssetsOptions = (TransformAssetsOptionsBase & {
|
|
85
63
|
transform: string | TransformAssetsFn;
|
|
86
64
|
createTransform?: never;
|
|
87
|
-
}) | (
|
|
65
|
+
}) | (TransformAssetsOptionsBase & {
|
|
88
66
|
createTransform: CreateTransformAssetsFn;
|
|
89
67
|
transform?: never;
|
|
90
68
|
});
|
|
91
|
-
export type TransformAssetUrls = string | TransformAssetUrlsFn | TransformAssetUrlsOptions;
|
|
92
69
|
/**
|
|
93
70
|
* Per-kind crossOrigin configuration for the object shorthand.
|
|
94
71
|
*
|
|
@@ -135,10 +112,7 @@ export type ResolvedTransformAssetsConfig = {
|
|
|
135
112
|
createTransform: CreateTransformAssetsFn;
|
|
136
113
|
cache: boolean;
|
|
137
114
|
};
|
|
138
|
-
export declare function warnDeprecatedTransformAssetUrls(): void;
|
|
139
115
|
export declare function resolveTransformAssetsConfig(transform: TransformAssets): ResolvedTransformAssetsConfig;
|
|
140
|
-
export declare function adaptTransformAssetUrlsToTransformAssets(transformFn: TransformAssetUrlsFn): TransformAssetsFn;
|
|
141
|
-
export declare function adaptTransformAssetUrlsConfigToTransformAssets(transform: TransformAssetUrls): TransformAssets;
|
|
142
116
|
export interface StartManifestWithClientEntry {
|
|
143
117
|
manifest: Manifest;
|
|
144
118
|
clientEntry: string;
|
|
@@ -152,11 +126,14 @@ export interface StartManifestWithClientEntry {
|
|
|
152
126
|
export declare function buildClientEntryScriptTag(clientEntry: string, injectedHeadScripts?: string): RouterManagedTag;
|
|
153
127
|
export declare function transformManifestAssets(source: StartManifestWithClientEntry, transformFn: TransformAssetsFn, _opts?: {
|
|
154
128
|
clone?: boolean;
|
|
129
|
+
inlineCss?: boolean;
|
|
155
130
|
}): Promise<Manifest>;
|
|
156
131
|
/**
|
|
157
132
|
* Builds a final Manifest from a StartManifestWithClientEntry without any
|
|
158
|
-
* URL transforms. Used when no
|
|
133
|
+
* URL transforms. Used when no transformAssets option is provided.
|
|
159
134
|
*
|
|
160
135
|
* Returns a new manifest object so the cached base manifest is never mutated.
|
|
161
136
|
*/
|
|
162
|
-
export declare function buildManifestWithClientEntry(source: StartManifestWithClientEntry
|
|
137
|
+
export declare function buildManifestWithClientEntry(source: StartManifestWithClientEntry, opts?: {
|
|
138
|
+
inlineCss?: boolean;
|
|
139
|
+
}): Manifest;
|