@tanstack/start-server-core 1.169.2 → 1.169.4
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/constants.js.map +1 -1
- package/dist/esm/createServerRpc.js.map +1 -1
- package/dist/esm/createSsrRpc.js.map +1 -1
- package/dist/esm/createStartHandler.js +1 -2
- package/dist/esm/createStartHandler.js.map +1 -1
- package/dist/esm/early-hints.d.ts +3 -3
- package/dist/esm/early-hints.js +16 -21
- package/dist/esm/early-hints.js.map +1 -1
- package/dist/esm/empty-plugin-adapters.d.ts +3 -0
- package/dist/esm/empty-plugin-adapters.js +7 -0
- package/dist/esm/empty-plugin-adapters.js.map +1 -0
- package/dist/esm/fake-start-server-fn-resolver.js.map +1 -1
- package/dist/esm/finalManifest.d.ts +4 -4
- package/dist/esm/finalManifest.js.map +1 -1
- package/dist/esm/frame-protocol.js.map +1 -1
- package/dist/esm/inlineCss.js.map +1 -1
- package/dist/esm/request-handler.d.ts +2 -1
- package/dist/esm/request-response.js.map +1 -1
- package/dist/esm/router-manifest.js +27 -30
- package/dist/esm/router-manifest.js.map +1 -1
- package/dist/esm/serializer/ServerFunctionSerializationAdapter.js.map +1 -1
- package/dist/esm/server-functions-handler.js.map +1 -1
- package/dist/esm/transformAssetUrls.d.ts +11 -16
- package/dist/esm/transformAssetUrls.js +80 -53
- package/dist/esm/transformAssetUrls.js.map +1 -1
- package/dist/esm/virtual-modules.d.ts +0 -1
- package/dist/esm/virtual-modules.js +0 -1
- package/dist/esm/virtual-modules.js.map +1 -1
- package/package.json +7 -4
- package/src/createStartHandler.ts +0 -1
- package/src/early-hints.ts +24 -24
- package/src/empty-plugin-adapters.ts +4 -0
- package/src/finalManifest.ts +14 -12
- package/src/request-handler.ts +2 -1
- package/src/router-manifest.ts +45 -47
- package/src/tanstack-start.d.ts +2 -6
- package/src/transformAssetUrls.ts +160 -91
- package/src/virtual-modules.ts +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformAssetUrls.js","names":[],"sources":["../../src/transformAssetUrls.ts"],"sourcesContent":["import { resolveManifestAssetLink, rootRouteId } from '@tanstack/router-core'\n\nimport type {\n AssetCrossOrigin,\n Awaitable,\n Manifest,\n ManifestAssetLink,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nexport type { AssetCrossOrigin }\n\nexport type TransformAssetsContext =\n | {\n url: string\n kind: 'modulepreload'\n }\n | {\n url: string\n kind: 'stylesheet'\n }\n | {\n url: string\n kind: 'clientEntry'\n }\n | {\n url: string\n kind: 'css-url'\n stylesheetHref: string\n }\n\nexport type TransformAssetKind = TransformAssetsContext['kind']\n\ntype TransformAssetsShorthandCrossOriginKind = Exclude<\n TransformAssetKind,\n 'clientEntry' | 'css-url'\n>\n\nexport type TransformAssetResult =\n | string\n | {\n href: string\n crossOrigin?: AssetCrossOrigin\n }\n\nexport type TransformAssetsFn = (\n context: TransformAssetsContext,\n) => Awaitable<TransformAssetResult>\n\nexport type CreateTransformAssetsContext =\n | {\n /** True when the server is computing the cached manifest during startup warmup. */\n warmup: true\n }\n | {\n /**\n * The current Request.\n *\n * Only available during request handling (i.e. when `warmup: false`).\n */\n request: Request\n /** False when transforming URLs as part of request handling. */\n warmup: false\n }\n\nexport type CreateTransformAssetsFn = (\n ctx: CreateTransformAssetsContext,\n) => Awaitable<TransformAssetsFn>\n\ntype TransformAssetsOptionsBase = {\n /**\n * Whether to cache the transformed manifest after the first request.\n *\n * When `true` (default), the transform runs once on the first request and\n * the resulting manifest is reused for all subsequent requests in production.\n *\n * Set to `false` for per-request transforms (e.g. geo-routing to different\n * CDNs based on request headers).\n *\n * @default true\n */\n cache?: boolean\n\n /**\n * When `true`, warms up the cached transformed manifest in the background when\n * the server starts (production only).\n *\n * This can reduce latency for the first request when `cache` is `true`.\n * Has no effect when `cache: false` (per-request transforms) or in dev mode.\n *\n * @default false\n */\n warmup?: boolean\n}\n\nexport type TransformAssetsOptions =\n | (TransformAssetsOptionsBase & {\n transform: string | TransformAssetsFn\n createTransform?: never\n })\n | (TransformAssetsOptionsBase & {\n createTransform: CreateTransformAssetsFn\n transform?: never\n })\n\n/**\n * Per-kind crossOrigin configuration for the object shorthand.\n *\n * Accepts either a single value applied to all asset kinds, or a per-kind\n * record (matching `HeadContent`'s `assetCrossOrigin` shape):\n *\n * ```ts\n * // All assets get the same value\n * crossOrigin: 'anonymous'\n *\n * // Different values per kind\n * crossOrigin: { modulepreload: 'anonymous', stylesheet: 'use-credentials' }\n * ```\n */\nexport type TransformAssetsCrossOriginConfig =\n | AssetCrossOrigin\n | Partial<Record<TransformAssetsShorthandCrossOriginKind, AssetCrossOrigin>>\n\n/**\n * Object shorthand for `transformAssets`. Combines a URL prefix with optional\n * per-asset `crossOrigin` without needing a callback:\n *\n * ```ts\n * transformAssets: {\n * prefix: 'https://cdn.example.com',\n * crossOrigin: 'anonymous',\n * }\n * ```\n */\nexport interface TransformAssetsObjectShorthand {\n /** URL prefix prepended to every asset URL. */\n prefix: string\n /**\n * Optional crossOrigin attribute applied to manifest-managed `<link>` assets.\n *\n * Accepts a single value or a per-kind record.\n */\n crossOrigin?: TransformAssetsCrossOriginConfig\n}\n\nexport type TransformAssets =\n | string\n | TransformAssetsFn\n | TransformAssetsObjectShorthand\n | TransformAssetsOptions\n\nexport type ResolvedTransformAssetsConfig =\n | {\n type: 'transform'\n transformFn: TransformAssetsFn\n cache: boolean\n }\n | {\n type: 'createTransform'\n createTransform: CreateTransformAssetsFn\n cache: boolean\n }\n\nfunction normalizeTransformAssetResult(\n result: TransformAssetResult,\n): Exclude<TransformAssetResult, string> {\n if (typeof result === 'string') {\n return { href: result }\n }\n\n return result\n}\n\nfunction escapeCssString(value: string) {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\a ')\n .replace(/\\r/g, '\\\\d ')\n .replace(/\\f/g, '\\\\c ')\n}\n\nasync function transformInlineCssTemplate(options: {\n stylesheetHref: string\n template: { strings: Array<string>; urls: Array<string> }\n transformFn: TransformAssetsFn\n}) {\n const { strings, urls } = options.template\n\n if (strings.length !== urls.length + 1) {\n throw new Error(\n `TanStack Start inlineCss template for ${options.stylesheetHref} is invalid`,\n )\n }\n\n let css = strings[0]!\n\n for (let index = 0; index < urls.length; index++) {\n const transformed = normalizeTransformAssetResult(\n await options.transformFn({\n kind: 'css-url',\n url: urls[index]!,\n stylesheetHref: options.stylesheetHref,\n }),\n )\n\n css += escapeCssString(transformed.href) + strings[index + 1]!\n }\n\n return css\n}\n\nasync function transformInlineCssStyles(\n inlineCss: NonNullable<Manifest['inlineCss']>,\n transformFn: TransformAssetsFn,\n) {\n const transformedStyles: Record<string, string> = {}\n\n const transformedEntries = await Promise.all(\n Object.entries(inlineCss.styles).map(async ([stylesheetHref, css]) => {\n const template = inlineCss.templates?.[stylesheetHref]\n return [\n stylesheetHref,\n template\n ? await transformInlineCssTemplate({\n stylesheetHref,\n template,\n transformFn,\n })\n : css,\n ] as const\n }),\n )\n\n for (const [stylesheetHref, css] of transformedEntries) {\n transformedStyles[stylesheetHref] = css\n }\n\n return {\n styles: transformedStyles,\n ...(inlineCss.templates ? { templates: inlineCss.templates } : {}),\n }\n}\n\nfunction resolveTransformAssetsCrossOrigin(\n config: TransformAssetsCrossOriginConfig | undefined,\n kind: TransformAssetsShorthandCrossOriginKind,\n): AssetCrossOrigin | undefined {\n if (!config) return undefined\n if (typeof config === 'string') return config\n\n return config[kind]\n}\n\nfunction isObjectShorthand(\n transform: TransformAssetsObjectShorthand | TransformAssetsOptions,\n): transform is TransformAssetsObjectShorthand {\n return 'prefix' in transform\n}\n\nexport function resolveTransformAssetsConfig(\n transform: TransformAssets,\n): ResolvedTransformAssetsConfig {\n if (typeof transform === 'string') {\n const prefix = transform\n return {\n type: 'transform',\n transformFn: ({ url }) => ({ href: `${prefix}${url}` }),\n cache: true,\n }\n }\n\n if (typeof transform === 'function') {\n return {\n type: 'transform',\n transformFn: transform,\n cache: true,\n }\n }\n\n // Object shorthand: { prefix, crossOrigin? }\n if (isObjectShorthand(transform)) {\n const { prefix, crossOrigin } = transform\n\n return {\n type: 'transform',\n transformFn: ({ url, kind }) => {\n const href = `${prefix}${url}`\n\n if (kind === 'clientEntry' || kind === 'css-url') {\n return { href }\n }\n\n const co = resolveTransformAssetsCrossOrigin(crossOrigin, kind)\n return co ? { href, crossOrigin: co } : { href }\n },\n cache: true,\n }\n }\n\n if ('createTransform' in transform && transform.createTransform) {\n return {\n type: 'createTransform',\n createTransform: transform.createTransform,\n cache: transform.cache !== false,\n }\n }\n\n const transformFn =\n typeof transform.transform === 'string'\n ? ((({ url }: TransformAssetsContext) => ({\n href: `${transform.transform}${url}`,\n })) as TransformAssetsFn)\n : transform.transform\n\n return {\n type: 'transform',\n transformFn,\n cache: transform.cache !== false,\n }\n}\n\nexport interface StartManifestWithClientEntry {\n manifest: Manifest\n clientEntry: string\n /** Script content prepended before the client entry import (dev only) */\n injectedHeadScripts?: string\n}\n\n/**\n * Builds the client entry `<script>` tag from a (possibly transformed) client\n * entry URL and optional injected head scripts.\n */\nexport function buildClientEntryScriptTag(\n clientEntry: string,\n injectedHeadScripts?: string,\n): RouterManagedTag {\n const clientEntryLiteral = JSON.stringify(clientEntry)\n let script = `import(${clientEntryLiteral})`\n if (injectedHeadScripts) {\n script = `${injectedHeadScripts};${script}`\n }\n return {\n tag: 'script',\n attrs: {\n type: 'module',\n async: true,\n },\n children: script,\n }\n}\n\nfunction assignManifestAssetLink(\n link: ManifestAssetLink,\n next: { href: string; crossOrigin?: AssetCrossOrigin },\n): ManifestAssetLink {\n if (typeof link === 'string') {\n return next.crossOrigin ? next : next.href\n }\n\n return next.crossOrigin ? next : { href: next.href }\n}\n\nexport async function transformManifestAssets(\n source: StartManifestWithClientEntry,\n transformFn: TransformAssetsFn,\n _opts?: {\n clone?: boolean\n inlineCss?: boolean\n },\n): Promise<Manifest> {\n const manifest = structuredClone(source.manifest)\n const inlineCssEnabled = _opts?.inlineCss !== false\n\n if (!inlineCssEnabled) {\n delete manifest.inlineCss\n } else if (manifest.inlineCss) {\n manifest.inlineCss = await transformInlineCssStyles(\n manifest.inlineCss,\n transformFn,\n )\n }\n\n for (const route of Object.values(manifest.routes)) {\n if (route.preloads) {\n route.preloads = await Promise.all(\n route.preloads.map(async (link) => {\n const resolved = resolveManifestAssetLink(link)\n const result = normalizeTransformAssetResult(\n await transformFn({\n url: resolved.href,\n kind: 'modulepreload',\n }),\n )\n\n return assignManifestAssetLink(link, {\n href: result.href,\n crossOrigin: result.crossOrigin,\n })\n }),\n )\n }\n\n if (route.assets && !manifest.inlineCss) {\n for (const asset of route.assets) {\n if (asset.tag === 'link' && asset.attrs?.href) {\n const rel = asset.attrs.rel\n const relTokens = typeof rel === 'string' ? rel.split(/\\s+/) : []\n\n if (!relTokens.includes('stylesheet')) {\n continue\n }\n\n const result = normalizeTransformAssetResult(\n await transformFn({\n url: asset.attrs.href,\n kind: 'stylesheet',\n }),\n )\n\n asset.attrs.href = result.href\n if (result.crossOrigin) {\n asset.attrs.crossOrigin = result.crossOrigin\n } else {\n delete asset.attrs.crossOrigin\n }\n }\n }\n }\n }\n\n const transformedClientEntry = normalizeTransformAssetResult(\n await transformFn({\n url: source.clientEntry,\n kind: 'clientEntry',\n }),\n )\n\n const rootRoute = (manifest.routes[rootRouteId] =\n manifest.routes[rootRouteId] || {})\n rootRoute.assets = rootRoute.assets || []\n rootRoute.assets.push(\n buildClientEntryScriptTag(\n transformedClientEntry.href,\n source.injectedHeadScripts,\n ),\n )\n\n return manifest\n}\n\n/**\n * Builds a final Manifest from a StartManifestWithClientEntry without any\n * URL transforms. Used when no transformAssets option is provided.\n *\n * Returns a new manifest object so the cached base manifest is never mutated.\n */\nexport function buildManifestWithClientEntry(\n source: StartManifestWithClientEntry,\n opts?: { inlineCss?: boolean },\n): Manifest {\n const scriptTag = buildClientEntryScriptTag(\n source.clientEntry,\n source.injectedHeadScripts,\n )\n\n const baseRootRoute = source.manifest.routes[rootRouteId]\n const routes = {\n ...source.manifest.routes,\n [rootRouteId]: {\n ...baseRootRoute,\n assets: [...(baseRootRoute?.assets || []), scriptTag],\n },\n }\n\n return {\n ...(opts?.inlineCss === false\n ? {}\n : { inlineCss: structuredClone(source.manifest.inlineCss) }),\n routes,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transformAssetUrls.js","names":[],"sources":["../../src/transformAssetUrls.ts"],"sourcesContent":["import {\n getManifestScriptFormat,\n resolveManifestAssetLink,\n resolveManifestCssLink,\n} from '@tanstack/router-core'\n\nimport type {\n AssetCrossOrigin,\n Awaitable,\n ManifestAssetLink,\n ManifestCssLink,\n ManifestScript,\n ScriptFormat,\n ServerManifest,\n} from '@tanstack/router-core'\n\nexport type { AssetCrossOrigin }\n\nexport type TransformAssetsContext =\n | {\n url: string\n kind: 'script'\n }\n | {\n url: string\n kind: 'stylesheet'\n }\n | {\n url: string\n kind: 'css-url'\n stylesheetHref: string\n }\n\nexport type TransformAssetKind = TransformAssetsContext['kind']\n\ntype TransformAssetsShorthandCrossOriginKind = Exclude<\n TransformAssetKind,\n 'css-url'\n>\n\nexport type TransformAssetResult =\n | string\n | {\n href: string\n crossOrigin?: AssetCrossOrigin\n }\n\nexport type TransformAssetsFn = (\n context: TransformAssetsContext,\n) => Awaitable<TransformAssetResult>\n\nexport type CreateTransformAssetsContext =\n | {\n /** True when the server is computing the cached manifest during startup warmup. */\n warmup: true\n }\n | {\n /**\n * The current Request.\n *\n * Only available during request handling (i.e. when `warmup: false`).\n */\n request: Request\n /** False when transforming URLs as part of request handling. */\n warmup: false\n }\n\nexport type CreateTransformAssetsFn = (\n ctx: CreateTransformAssetsContext,\n) => Awaitable<TransformAssetsFn>\n\ntype TransformAssetsOptionsBase = {\n /**\n * Whether to cache the transformed manifest after the first request.\n *\n * When `true` (default), the transform runs once on the first request and\n * the resulting manifest is reused for all subsequent requests in production.\n *\n * Set to `false` for per-request transforms (e.g. geo-routing to different\n * CDNs based on request headers).\n *\n * @default true\n */\n cache?: boolean\n\n /**\n * When `true`, warms up the cached transformed manifest in the background when\n * the server starts (production only).\n *\n * This can reduce latency for the first request when `cache` is `true`.\n * Has no effect when `cache: false` (per-request transforms) or in dev mode.\n *\n * @default false\n */\n warmup?: boolean\n}\n\nexport type TransformAssetsOptions =\n | (TransformAssetsOptionsBase & {\n transform: string | TransformAssetsFn\n createTransform?: never\n })\n | (TransformAssetsOptionsBase & {\n createTransform: CreateTransformAssetsFn\n transform?: never\n })\n\n/**\n * Per-kind crossOrigin configuration for the object shorthand.\n *\n * Accepts either a single value applied to all asset kinds, or a per-kind\n * record (matching `HeadContent`'s `assetCrossOrigin` shape):\n *\n * ```ts\n * // All assets get the same value\n * crossOrigin: 'anonymous'\n *\n * // Different values per kind\n * crossOrigin: { script: 'anonymous', stylesheet: 'use-credentials' }\n * ```\n */\nexport type TransformAssetsCrossOriginConfig =\n | AssetCrossOrigin\n | Partial<Record<TransformAssetsShorthandCrossOriginKind, AssetCrossOrigin>>\n\n/**\n * Object shorthand for `transformAssets`. Combines a URL prefix with optional\n * per-asset `crossOrigin` without needing a callback:\n *\n * ```ts\n * transformAssets: {\n * prefix: 'https://cdn.example.com',\n * crossOrigin: 'anonymous',\n * }\n * ```\n */\nexport interface TransformAssetsObjectShorthand {\n /** URL prefix prepended to every asset URL. */\n prefix: string\n /**\n * Optional crossOrigin attribute applied to transformed script and stylesheet assets.\n *\n * Accepts a single value or a per-kind record.\n */\n crossOrigin?: TransformAssetsCrossOriginConfig\n}\n\nexport type TransformAssets =\n | string\n | TransformAssetsFn\n | TransformAssetsObjectShorthand\n | TransformAssetsOptions\n\nexport type ResolvedTransformAssetsConfig =\n | {\n type: 'transform'\n transformFn: TransformAssetsFn\n cache: boolean\n }\n | {\n type: 'createTransform'\n createTransform: CreateTransformAssetsFn\n cache: boolean\n }\n\nfunction normalizeTransformAssetResult(\n result: TransformAssetResult,\n): Exclude<TransformAssetResult, string> {\n if (typeof result === 'string') {\n return { href: result }\n }\n\n return result\n}\n\nfunction escapeCssString(value: string) {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\a ')\n .replace(/\\r/g, '\\\\d ')\n .replace(/\\f/g, '\\\\c ')\n}\n\nasync function transformInlineCssTemplate(options: {\n stylesheetHref: string\n template: { strings: Array<string>; urls: Array<string> }\n transformFn: TransformAssetsFn\n}) {\n const { strings, urls } = options.template\n\n if (strings.length !== urls.length + 1) {\n throw new Error(\n `TanStack Start inlineCss template for ${options.stylesheetHref} is invalid`,\n )\n }\n\n let css = strings[0]!\n\n for (let index = 0; index < urls.length; index++) {\n const transformed = normalizeTransformAssetResult(\n await options.transformFn({\n kind: 'css-url',\n url: urls[index]!,\n stylesheetHref: options.stylesheetHref,\n }),\n )\n\n css += escapeCssString(transformed.href) + strings[index + 1]!\n }\n\n return css\n}\n\nasync function transformInlineCssStyles(\n inlineCss: NonNullable<ServerManifest['inlineCss']>,\n transformFn: TransformAssetsFn,\n) {\n const transformedStyles: Record<string, string> = {}\n\n const transformedEntries = await Promise.all(\n Object.entries(inlineCss.styles).map(async ([stylesheetHref, css]) => {\n const template = inlineCss.templates?.[stylesheetHref]\n return [\n stylesheetHref,\n template\n ? await transformInlineCssTemplate({\n stylesheetHref,\n template,\n transformFn,\n })\n : css,\n ] as const\n }),\n )\n\n for (const [stylesheetHref, css] of transformedEntries) {\n transformedStyles[stylesheetHref] = css\n }\n\n return {\n styles: transformedStyles,\n ...(inlineCss.templates ? { templates: inlineCss.templates } : {}),\n }\n}\n\nfunction resolveTransformAssetsCrossOrigin(\n config: TransformAssetsCrossOriginConfig | undefined,\n kind: TransformAssetsShorthandCrossOriginKind,\n): AssetCrossOrigin | undefined {\n if (!config) return undefined\n if (typeof config === 'string') return config\n\n return config[kind]\n}\n\nfunction isObjectShorthand(\n transform: TransformAssetsObjectShorthand | TransformAssetsOptions,\n): transform is TransformAssetsObjectShorthand {\n return 'prefix' in transform\n}\n\nexport function resolveTransformAssetsConfig(\n transform: TransformAssets,\n): ResolvedTransformAssetsConfig {\n if (typeof transform === 'string') {\n const prefix = transform\n return {\n type: 'transform',\n transformFn: ({ url }) => ({ href: `${prefix}${url}` }),\n cache: true,\n }\n }\n\n if (typeof transform === 'function') {\n return {\n type: 'transform',\n transformFn: transform,\n cache: true,\n }\n }\n\n // Object shorthand: { prefix, crossOrigin? }\n if (isObjectShorthand(transform)) {\n const { prefix, crossOrigin } = transform\n\n return {\n type: 'transform',\n transformFn: ({ url, kind }) => {\n const href = `${prefix}${url}`\n\n if (kind === 'css-url') {\n return { href }\n }\n\n const co = resolveTransformAssetsCrossOrigin(crossOrigin, kind)\n return co ? { href, crossOrigin: co } : { href }\n },\n cache: true,\n }\n }\n\n if ('createTransform' in transform && transform.createTransform) {\n return {\n type: 'createTransform',\n createTransform: transform.createTransform,\n cache: transform.cache !== false,\n }\n }\n\n const transformFn =\n typeof transform.transform === 'string'\n ? ((({ url }: TransformAssetsContext) => ({\n href: `${transform.transform}${url}`,\n })) as TransformAssetsFn)\n : transform.transform\n\n return {\n type: 'transform',\n transformFn,\n cache: transform.cache !== false,\n }\n}\n\nexport interface StartManifestWithClientEntry {\n manifest: ServerManifest\n clientEntry: string\n}\n\n/**\n * Builds the client entry `<script>` tag from a (possibly transformed) client\n * entry URL.\n */\nexport function buildClientEntryScriptTag(\n clientEntry: string,\n scriptFormat: ScriptFormat = 'module',\n crossOrigin?: AssetCrossOrigin,\n): ManifestScript {\n return {\n attrs: {\n ...(scriptFormat === 'module' ? { type: 'module' } : {}),\n async: true,\n src: clientEntry,\n ...(crossOrigin ? { crossOrigin } : {}),\n },\n }\n}\n\ntype AssignableManifestLink = ManifestAssetLink | ManifestCssLink\n\nfunction assignManifestLink(\n link: ManifestAssetLink,\n next: { href: string; crossOrigin?: AssetCrossOrigin },\n): ManifestAssetLink\nfunction assignManifestLink(\n link: ManifestCssLink,\n next: { href: string; crossOrigin?: AssetCrossOrigin },\n): ManifestCssLink\nfunction assignManifestLink(\n link: AssignableManifestLink,\n next: { href: string; crossOrigin?: AssetCrossOrigin },\n): AssignableManifestLink {\n if (typeof link === 'string') {\n return next.crossOrigin ? next : next.href\n }\n\n const nextLink: Exclude<ManifestCssLink, string> = {\n ...link,\n href: next.href,\n }\n\n if (next.crossOrigin) {\n nextLink.crossOrigin = next.crossOrigin\n } else {\n delete nextLink.crossOrigin\n }\n\n return nextLink\n}\n\nfunction appendUniqueManifestAssetLink(\n target: Array<ManifestAssetLink> | undefined,\n link: ManifestAssetLink,\n) {\n const href = typeof link === 'string' ? link : link.href\n\n if (target) {\n for (const item of target) {\n if ((typeof item === 'string' ? item : item.href) === href) {\n return target\n }\n }\n }\n\n return [...(target ?? []), link]\n}\n\nfunction addClientEntryToManifest(\n manifest: ServerManifest,\n clientEntry: string,\n) {\n const rootRoute = manifest.routes.__root__ ?? {}\n const rootScripts = rootRoute.scripts ?? []\n const scripts = rootScripts.some(\n (script) => script.attrs?.src === clientEntry,\n )\n ? rootScripts\n : [\n ...rootScripts,\n buildClientEntryScriptTag(\n clientEntry,\n getManifestScriptFormat(manifest),\n ),\n ]\n\n manifest.routes = {\n ...manifest.routes,\n __root__: {\n ...rootRoute,\n preloads: appendUniqueManifestAssetLink(rootRoute.preloads, clientEntry),\n scripts,\n },\n }\n}\n\nexport async function transformManifestAssets(\n source: StartManifestWithClientEntry,\n transformFn: TransformAssetsFn,\n _opts?: {\n clone?: boolean\n inlineCss?: boolean\n },\n): Promise<ServerManifest> {\n const manifest = structuredClone(source.manifest)\n const inlineCssEnabled = _opts?.inlineCss !== false\n const scriptTransforms = new Map<\n string,\n Promise<Exclude<TransformAssetResult, string>>\n >()\n const transformScript = (url: string) => {\n const cached = scriptTransforms.get(url)\n if (cached) {\n return cached\n }\n\n const transformed = Promise.resolve(\n transformFn({\n url,\n kind: 'script',\n }),\n ).then(normalizeTransformAssetResult)\n scriptTransforms.set(url, transformed)\n return transformed\n }\n\n if (!inlineCssEnabled) {\n delete manifest.inlineCss\n } else if (manifest.inlineCss) {\n manifest.inlineCss = await transformInlineCssStyles(\n manifest.inlineCss,\n transformFn,\n )\n }\n\n addClientEntryToManifest(manifest, source.clientEntry)\n\n for (const route of Object.values(manifest.routes)) {\n if (route.preloads?.length) {\n route.preloads = await Promise.all(\n route.preloads.map(async (link) => {\n const resolved = resolveManifestAssetLink(link)\n const result = await transformScript(resolved.href)\n\n return assignManifestLink(link, {\n href: result.href,\n crossOrigin: result.crossOrigin,\n })\n }),\n )\n }\n\n if (route.css?.length && !manifest.inlineCss) {\n route.css = await Promise.all(\n route.css.map(async (link) => {\n const resolved = resolveManifestCssLink(link)\n const result = normalizeTransformAssetResult(\n await transformFn({\n url: resolved.href,\n kind: 'stylesheet',\n }),\n )\n\n return assignManifestLink(link, {\n href: result.href,\n crossOrigin: result.crossOrigin,\n })\n }),\n )\n }\n\n if (route.scripts?.length) {\n for (const script of route.scripts) {\n const src = script.attrs?.src\n if (typeof src !== 'string') {\n continue\n }\n\n const result = await transformScript(src)\n\n script.attrs = {\n ...script.attrs,\n src: result.href,\n }\n if (result.crossOrigin) {\n script.attrs.crossOrigin = result.crossOrigin\n } else {\n delete script.attrs.crossOrigin\n }\n }\n }\n }\n\n return manifest\n}\n\n/**\n * Builds a final ServerManifest from a StartManifestWithClientEntry without any\n * URL transforms. Used when no transformAssets option is provided.\n *\n * Returns a new manifest object so the cached base manifest is never mutated.\n */\nexport function buildManifestWithClientEntry(\n source: StartManifestWithClientEntry,\n opts?: { inlineCss?: boolean },\n): ServerManifest {\n const manifest: ServerManifest = {\n ...(source.manifest.scriptFormat\n ? { scriptFormat: source.manifest.scriptFormat }\n : {}),\n ...(opts?.inlineCss !== false && source.manifest.inlineCss\n ? { inlineCss: structuredClone(source.manifest.inlineCss) }\n : {}),\n routes: {\n ...source.manifest.routes,\n },\n }\n\n addClientEntryToManifest(manifest, source.clientEntry)\n\n return manifest\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export declare const VIRTUAL_MODULES: {
|
|
2
2
|
readonly startManifest: "tanstack-start-manifest:v";
|
|
3
|
-
readonly injectedHeadScripts: "tanstack-start-injected-head-scripts:v";
|
|
4
3
|
readonly serverFnResolver: "#tanstack-start-server-fn-resolver";
|
|
5
4
|
readonly pluginAdapters: "#tanstack-start-plugin-adapters";
|
|
6
5
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
//#region src/virtual-modules.ts
|
|
2
2
|
var VIRTUAL_MODULES = {
|
|
3
3
|
startManifest: "tanstack-start-manifest:v",
|
|
4
|
-
injectedHeadScripts: "tanstack-start-injected-head-scripts:v",
|
|
5
4
|
serverFnResolver: "#tanstack-start-server-fn-resolver",
|
|
6
5
|
pluginAdapters: "#tanstack-start-plugin-adapters"
|
|
7
6
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtual-modules.js","names":[],"sources":["../../src/virtual-modules.ts"],"sourcesContent":["export const VIRTUAL_MODULES = {\n startManifest: 'tanstack-start-manifest:v',\n
|
|
1
|
+
{"version":3,"file":"virtual-modules.js","names":[],"sources":["../../src/virtual-modules.ts"],"sourcesContent":["export const VIRTUAL_MODULES = {\n startManifest: 'tanstack-start-manifest:v',\n serverFnResolver: '#tanstack-start-server-fn-resolver',\n pluginAdapters: '#tanstack-start-plugin-adapters',\n} as const\n"],"mappings":";AAAA,IAAa,kBAAkB;CAC7B,eAAe;CACf,kBAAkB;CAClB,gBAAgB;AAClB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/start-server-core",
|
|
3
|
-
"version": "1.169.
|
|
3
|
+
"version": "1.169.4",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,6 +49,9 @@
|
|
|
49
49
|
"imports": {
|
|
50
50
|
"#tanstack-start-server-fn-resolver": {
|
|
51
51
|
"default": "./dist/esm/fake-start-server-fn-resolver.js"
|
|
52
|
+
},
|
|
53
|
+
"#tanstack-start-plugin-adapters": {
|
|
54
|
+
"default": "./dist/esm/empty-plugin-adapters.js"
|
|
52
55
|
}
|
|
53
56
|
},
|
|
54
57
|
"sideEffects": false,
|
|
@@ -67,9 +70,9 @@
|
|
|
67
70
|
"h3-v2": "npm:h3@2.0.1-rc.20",
|
|
68
71
|
"seroval": "^1.5.4",
|
|
69
72
|
"@tanstack/history": "1.162.0",
|
|
70
|
-
"@tanstack/router-core": "1.171.
|
|
71
|
-
"@tanstack/start-client-core": "1.170.
|
|
72
|
-
"@tanstack/start-storage-context": "1.167.
|
|
73
|
+
"@tanstack/router-core": "1.171.6",
|
|
74
|
+
"@tanstack/start-client-core": "1.170.4",
|
|
75
|
+
"@tanstack/start-storage-context": "1.167.8"
|
|
73
76
|
},
|
|
74
77
|
"devDependencies": {
|
|
75
78
|
"@standard-schema/spec": "^1.0.0",
|
|
@@ -497,7 +497,6 @@ export function createStartHandler<TRegister = Register>(
|
|
|
497
497
|
manifest,
|
|
498
498
|
getRequestAssets: () =>
|
|
499
499
|
getStartContext({ throwIfNotFound: false })?.requestAssets,
|
|
500
|
-
includeUnmatchedRouteAssets: false,
|
|
501
500
|
})
|
|
502
501
|
|
|
503
502
|
routerInstance.update({ additionalContext: { serverContext } })
|
package/src/early-hints.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
getScriptPreloadAttrs,
|
|
2
3
|
getStylesheetHref,
|
|
3
|
-
|
|
4
|
+
resolveManifestCssLink,
|
|
4
5
|
} from '@tanstack/router-core'
|
|
5
6
|
import type {
|
|
6
7
|
AnyRoute,
|
|
7
8
|
AnyRouteMatch,
|
|
8
9
|
AssetCrossOrigin,
|
|
9
|
-
Manifest,
|
|
10
10
|
RouterManagedTag,
|
|
11
|
+
ServerManifest,
|
|
11
12
|
} from '@tanstack/router-core'
|
|
12
13
|
|
|
13
14
|
export type EarlyHint = {
|
|
@@ -49,7 +50,7 @@ export type ResponseLinkHeaderOptions = {
|
|
|
49
50
|
|
|
50
51
|
export interface EarlyHintsCollector {
|
|
51
52
|
collectStatic: (opts: {
|
|
52
|
-
manifest:
|
|
53
|
+
manifest: ServerManifest
|
|
53
54
|
matchedRoutes?: ReadonlyArray<AnyRoute>
|
|
54
55
|
}) => void
|
|
55
56
|
collectDynamic: (matches: ReadonlyArray<AnyRouteMatch>) => void
|
|
@@ -174,7 +175,7 @@ function linkAttrsToEarlyHint(
|
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
export function collectStaticHintsFromManifest(
|
|
177
|
-
manifest:
|
|
178
|
+
manifest: ServerManifest,
|
|
178
179
|
matchedRoutes: ReadonlyArray<AnyRoute>,
|
|
179
180
|
): Array<EarlyHint> {
|
|
180
181
|
const hints: Array<EarlyHint> = []
|
|
@@ -184,33 +185,32 @@ export function collectStaticHintsFromManifest(
|
|
|
184
185
|
if (!routeManifest) continue
|
|
185
186
|
|
|
186
187
|
for (const link of routeManifest.preloads ?? []) {
|
|
187
|
-
const
|
|
188
|
-
const hint: EarlyHint = {
|
|
189
|
-
|
|
188
|
+
const attrs = getScriptPreloadAttrs(manifest, link)
|
|
189
|
+
const hint: EarlyHint = {
|
|
190
|
+
href: attrs.href,
|
|
191
|
+
rel: attrs.rel,
|
|
192
|
+
as: 'script',
|
|
193
|
+
}
|
|
194
|
+
if (attrs.crossOrigin !== undefined) hint.crossOrigin = attrs.crossOrigin
|
|
190
195
|
hints.push(hint)
|
|
191
196
|
}
|
|
192
197
|
|
|
193
|
-
for (const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const stylesheetHref = getStylesheetHref(asset)
|
|
197
|
-
if (stylesheetHref) {
|
|
198
|
-
if (manifest.inlineCss?.styles[stylesheetHref] !== undefined) continue
|
|
199
|
-
|
|
200
|
-
const hint: EarlyHint = {
|
|
201
|
-
href: stylesheetHref,
|
|
202
|
-
rel: 'preload',
|
|
203
|
-
as: 'style',
|
|
204
|
-
}
|
|
205
|
-
addEarlyHintFetchAttrs(hint, asset.attrs)
|
|
206
|
-
hints.push(hint)
|
|
198
|
+
for (const link of routeManifest.css ?? []) {
|
|
199
|
+
const stylesheetHref = getStylesheetHref(link)
|
|
200
|
+
if (manifest.inlineCss?.styles[stylesheetHref] !== undefined) {
|
|
207
201
|
continue
|
|
208
202
|
}
|
|
203
|
+
const resolvedLink = resolveManifestCssLink(link)
|
|
209
204
|
|
|
210
|
-
const hint =
|
|
211
|
-
|
|
212
|
-
|
|
205
|
+
const hint: EarlyHint = {
|
|
206
|
+
href: stylesheetHref,
|
|
207
|
+
rel: 'preload',
|
|
208
|
+
as: 'style',
|
|
213
209
|
}
|
|
210
|
+
if (resolvedLink.crossOrigin !== undefined) {
|
|
211
|
+
hint.crossOrigin = resolvedLink.crossOrigin
|
|
212
|
+
}
|
|
213
|
+
hints.push(hint)
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
package/src/finalManifest.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getStaticHandlerInlineCssDefault,
|
|
8
8
|
resolveInlineCssForRequest,
|
|
9
9
|
} from './inlineCss'
|
|
10
|
-
import type {
|
|
10
|
+
import type { ServerManifest } from '@tanstack/router-core'
|
|
11
11
|
import type { HandlerInlineCssOption } from './inlineCss'
|
|
12
12
|
import type {
|
|
13
13
|
CreateTransformAssetsContext,
|
|
@@ -45,7 +45,7 @@ export interface FinalManifestOptions {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
type FinalManifestCacheKey = 'inline-css' | 'linked-css'
|
|
48
|
-
type FinalManifestCache = Map<FinalManifestCacheKey, Promise<
|
|
48
|
+
type FinalManifestCache = Map<FinalManifestCacheKey, Promise<ServerManifest>>
|
|
49
49
|
export type GetBaseManifest = () => Promise<StartManifestWithClientEntry>
|
|
50
50
|
|
|
51
51
|
export interface FinalManifestRequestOptions {
|
|
@@ -66,9 +66,11 @@ interface FinalManifestTransformResolver {
|
|
|
66
66
|
export interface FinalManifestResolver {
|
|
67
67
|
warmup: (opts: {
|
|
68
68
|
getBaseManifest: GetBaseManifest
|
|
69
|
-
}) => Promise<
|
|
70
|
-
resolveCached: (opts: FinalManifestRequestOptions) => Promise<
|
|
71
|
-
resolveUncached: (
|
|
69
|
+
}) => Promise<ServerManifest> | undefined
|
|
70
|
+
resolveCached: (opts: FinalManifestRequestOptions) => Promise<ServerManifest>
|
|
71
|
+
resolveUncached: (
|
|
72
|
+
opts: FinalManifestRequestOptions,
|
|
73
|
+
) => Promise<ServerManifest>
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
export function createCachedBaseManifestLoader(
|
|
@@ -206,8 +208,8 @@ function getFinalManifestCacheKey(inlineCss: boolean): FinalManifestCacheKey {
|
|
|
206
208
|
function cacheFinalManifestPromise(
|
|
207
209
|
cachedFinalManifestPromises: FinalManifestCache,
|
|
208
210
|
cacheKey: FinalManifestCacheKey,
|
|
209
|
-
promise: Promise<
|
|
210
|
-
): Promise<
|
|
211
|
+
promise: Promise<ServerManifest>,
|
|
212
|
+
): Promise<ServerManifest> {
|
|
211
213
|
const cachedFinalManifestPromise = promise.catch((error) => {
|
|
212
214
|
if (
|
|
213
215
|
cachedFinalManifestPromises.get(cacheKey) === cachedFinalManifestPromise
|
|
@@ -224,8 +226,8 @@ function cacheFinalManifestPromise(
|
|
|
224
226
|
function getOrCreateCachedFinalManifestPromise(
|
|
225
227
|
cachedFinalManifestPromises: FinalManifestCache,
|
|
226
228
|
cacheKey: FinalManifestCacheKey,
|
|
227
|
-
computeFinalManifest: () => Promise<
|
|
228
|
-
): Promise<
|
|
229
|
+
computeFinalManifest: () => Promise<ServerManifest>,
|
|
230
|
+
): Promise<ServerManifest> {
|
|
229
231
|
const cachedFinalManifestPromise = cachedFinalManifestPromises.get(cacheKey)
|
|
230
232
|
if (cachedFinalManifestPromise) {
|
|
231
233
|
return cachedFinalManifestPromise
|
|
@@ -242,7 +244,7 @@ async function buildFinalManifest(opts: {
|
|
|
242
244
|
base: StartManifestWithClientEntry
|
|
243
245
|
transformFn: TransformAssetsFn | undefined
|
|
244
246
|
inlineCss: boolean
|
|
245
|
-
}): Promise<
|
|
247
|
+
}): Promise<ServerManifest> {
|
|
246
248
|
return opts.transformFn
|
|
247
249
|
? await transformManifestAssets(opts.base, opts.transformFn, {
|
|
248
250
|
inlineCss: opts.inlineCss,
|
|
@@ -256,7 +258,7 @@ async function resolveFinalManifest(opts: {
|
|
|
256
258
|
cache: boolean
|
|
257
259
|
inlineCss: boolean
|
|
258
260
|
finalManifestCache?: FinalManifestCache
|
|
259
|
-
}): Promise<
|
|
261
|
+
}): Promise<ServerManifest> {
|
|
260
262
|
const computeFinalManifest = async () => {
|
|
261
263
|
return buildFinalManifest({
|
|
262
264
|
base: await opts.getBaseManifest(),
|
|
@@ -284,7 +286,7 @@ function warmupFinalManifest(opts: {
|
|
|
284
286
|
getBaseManifest: () => Promise<StartManifestWithClientEntry>
|
|
285
287
|
getTransformFn: () => Promise<TransformAssetsFn | undefined>
|
|
286
288
|
onError?: () => void
|
|
287
|
-
}): Promise<
|
|
289
|
+
}): Promise<ServerManifest> | undefined {
|
|
288
290
|
if (
|
|
289
291
|
!opts.enabled ||
|
|
290
292
|
opts.handlerDefaultInlineCss === undefined ||
|
package/src/request-handler.ts
CHANGED
|
@@ -9,7 +9,8 @@ type EarlyHintsOptions = {
|
|
|
9
9
|
* Fire-and-forget callback for HTTP 103 Early Hints.
|
|
10
10
|
* Only invoked in production (when TSS_DEV_SERVER !== 'true').
|
|
11
11
|
*
|
|
12
|
-
* The `static` phase contains transformed manifest
|
|
12
|
+
* The `static` phase contains transformed manifest preloads and stylesheets
|
|
13
|
+
* for matched routes.
|
|
13
14
|
* The `dynamic` phase runs after route load, is skipped for redirects, and
|
|
14
15
|
* can contain route `head().links` or empty `hints` and `links` arrays.
|
|
15
16
|
* `hints` and `links` contain only values not emitted in earlier phases.
|
package/src/router-manifest.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
RouterManagedTag,
|
|
1
|
+
import {
|
|
2
|
+
DEV_STYLES_ATTR,
|
|
3
|
+
buildDevStylesUrl,
|
|
4
|
+
rootRouteId,
|
|
6
5
|
} from '@tanstack/router-core'
|
|
6
|
+
import type { AnyRoute, ServerManifestRoute } from '@tanstack/router-core'
|
|
7
7
|
import type { StartManifestWithClientEntry } from './transformAssetUrls'
|
|
8
8
|
|
|
9
9
|
// Pre-computed constant for dev styles URL basepath.
|
|
10
10
|
// Defaults to vite `base` (set via TSS_DEV_SSR_STYLES_BASEPATH in the plugin),
|
|
11
11
|
// aligning dev styles with how other CSS/JS assets are served.
|
|
12
12
|
const DEV_SSR_STYLES_BASEPATH = process.env.TSS_DEV_SSR_STYLES_BASEPATH || '/'
|
|
13
|
-
|
|
14
13
|
/**
|
|
15
14
|
* @description Returns the router manifest data that should be sent to the client.
|
|
16
15
|
* This includes only the assets and preloads for the current route and any
|
|
@@ -28,11 +27,16 @@ export async function getStartManifest(
|
|
|
28
27
|
): Promise<StartManifestWithClientEntry> {
|
|
29
28
|
const { tsrStartManifest } = await import('tanstack-start-manifest:v')
|
|
30
29
|
const startManifest = tsrStartManifest()
|
|
30
|
+
let routes = startManifest.routes
|
|
31
|
+
let rootRoute = routes[rootRouteId]
|
|
31
32
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const updateRootRoute = (nextRootRoute: ServerManifestRoute) => {
|
|
34
|
+
rootRoute = nextRootRoute
|
|
35
|
+
routes = {
|
|
36
|
+
...routes,
|
|
37
|
+
[rootRouteId]: rootRoute,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
36
40
|
|
|
37
41
|
// Inject dev styles link in dev mode (when SSR styles are enabled)
|
|
38
42
|
if (
|
|
@@ -41,54 +45,48 @@ export async function getStartManifest(
|
|
|
41
45
|
matchedRoutes
|
|
42
46
|
) {
|
|
43
47
|
const matchedRouteIds = matchedRoutes.map((route) => route.id)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
updateRootRoute({
|
|
49
|
+
...rootRoute,
|
|
50
|
+
css: [
|
|
51
|
+
...(rootRoute?.css ?? []),
|
|
52
|
+
{
|
|
53
|
+
href: buildDevStylesUrl(DEV_SSR_STYLES_BASEPATH, matchedRouteIds),
|
|
54
|
+
[DEV_STYLES_ATTR]: true,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
51
57
|
})
|
|
52
58
|
}
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
const manifestRoutes: Record<string, ServerManifestRoute> = {}
|
|
61
|
+
|
|
62
|
+
for (const k in routes) {
|
|
63
|
+
const v = routes[k]!
|
|
64
|
+
const result = {} as ServerManifestRoute
|
|
65
|
+
|
|
66
|
+
if (v.preloads && v.preloads.length > 0) {
|
|
67
|
+
result.preloads = v.preloads
|
|
68
|
+
}
|
|
69
|
+
if (v.scripts && v.scripts.length > 0) {
|
|
70
|
+
result.scripts = v.scripts
|
|
71
|
+
}
|
|
72
|
+
if (v.css?.length) {
|
|
73
|
+
result.css = v.css
|
|
74
|
+
}
|
|
75
|
+
if (result.preloads || result.scripts || result.css) {
|
|
76
|
+
manifestRoutes[k] = result
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
|
|
64
80
|
const manifest = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
assets?: Array<RouterManagedTag>
|
|
71
|
-
}
|
|
72
|
-
let hasData = false
|
|
73
|
-
if (v.preloads && v.preloads.length > 0) {
|
|
74
|
-
result['preloads'] = v.preloads
|
|
75
|
-
hasData = true
|
|
76
|
-
}
|
|
77
|
-
if (v.assets && v.assets.length > 0) {
|
|
78
|
-
result['assets'] = v.assets
|
|
79
|
-
hasData = true
|
|
80
|
-
}
|
|
81
|
-
if (!hasData) {
|
|
82
|
-
return []
|
|
83
|
-
}
|
|
84
|
-
return [[k, result]]
|
|
85
|
-
}),
|
|
86
|
-
),
|
|
81
|
+
...(startManifest.scriptFormat
|
|
82
|
+
? { scriptFormat: startManifest.scriptFormat }
|
|
83
|
+
: {}),
|
|
84
|
+
...(startManifest.inlineCss ? { inlineCss: startManifest.inlineCss } : {}),
|
|
85
|
+
routes: manifestRoutes,
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
return {
|
|
90
89
|
manifest: manifest as StartManifestWithClientEntry['manifest'],
|
|
91
90
|
clientEntry: startManifest.clientEntry,
|
|
92
|
-
injectedHeadScripts,
|
|
93
91
|
}
|
|
94
92
|
}
|
package/src/tanstack-start.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
declare module 'tanstack-start-manifest:v' {
|
|
2
|
-
import type {
|
|
2
|
+
import type { ServerManifest } from '@tanstack/router-core'
|
|
3
3
|
|
|
4
|
-
export const tsrStartManifest: () =>
|
|
4
|
+
export const tsrStartManifest: () => ServerManifest & { clientEntry: string }
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
declare module 'tanstack-start-route-tree:v' {
|
|
@@ -21,7 +21,3 @@ declare module '#tanstack-start-server-fn-resolver' {
|
|
|
21
21
|
access: ServerFnLookupAccess,
|
|
22
22
|
): Promise<ServerFn>
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
declare module 'tanstack-start-injected-head-scripts:v' {
|
|
26
|
-
export const injectedHeadScripts: string | undefined
|
|
27
|
-
}
|