UNPKG

@tanstack/start-server-core

Version:

Modern and scalable routing for React applications

163 lines (162 loc) 5.65 kB
import { resolveManifestAssetLink, resolveManifestCssLink } from "@tanstack/router-core"; //#region src/transformAssetUrls.ts function normalizeTransformAssetResult(result) { if (typeof result === "string") return { href: result }; return result; } function escapeCssString(value) { return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\a ").replace(/\r/g, "\\d ").replace(/\f/g, "\\c "); } async function transformInlineCssTemplate(options) { const { strings, urls } = options.template; if (strings.length !== urls.length + 1) throw new Error(`TanStack Start inlineCss template for ${options.stylesheetHref} is invalid`); let css = strings[0]; for (let index = 0; index < urls.length; index++) { const transformed = normalizeTransformAssetResult(await options.transformFn({ kind: "css-url", url: urls[index], stylesheetHref: options.stylesheetHref })); css += escapeCssString(transformed.href) + strings[index + 1]; } return css; } async function transformInlineCssStyles(inlineCss, transformFn) { const transformedStyles = {}; const transformedEntries = await Promise.all(Object.entries(inlineCss.styles).map(async ([stylesheetHref, css]) => { const template = inlineCss.templates?.[stylesheetHref]; return [stylesheetHref, template ? await transformInlineCssTemplate({ stylesheetHref, template, transformFn }) : css]; })); for (const [stylesheetHref, css] of transformedEntries) transformedStyles[stylesheetHref] = css; return { styles: transformedStyles, ...inlineCss.templates ? { templates: inlineCss.templates } : {} }; } function resolveTransformAssetsCrossOrigin(config, kind) { if (!config) return void 0; if (typeof config === "string") return config; return config[kind]; } function isObjectShorthand(transform) { return "prefix" in transform; } function resolveTransformAssetsConfig(transform) { if (typeof transform === "string") { const prefix = transform; return { type: "transform", transformFn: ({ url }) => ({ href: `${prefix}${url}` }), cache: true }; } if (typeof transform === "function") return { type: "transform", transformFn: transform, cache: true }; if (isObjectShorthand(transform)) { const { prefix, crossOrigin } = transform; return { type: "transform", transformFn: ({ url, kind }) => { const href = `${prefix}${url}`; if (kind === "css-url") return { href }; const co = resolveTransformAssetsCrossOrigin(crossOrigin, kind); return co ? { href, crossOrigin: co } : { href }; }, cache: true }; } if ("createTransform" in transform && transform.createTransform) return { type: "createTransform", createTransform: transform.createTransform, cache: transform.cache !== false }; return { type: "transform", transformFn: typeof transform.transform === "string" ? (({ url }) => ({ href: `${transform.transform}${url}` })) : transform.transform, cache: transform.cache !== false }; } function assignManifestLink(link, next) { if (typeof link === "string") return next.crossOrigin ? next : next.href; const nextLink = { ...link, href: next.href }; if (next.crossOrigin) nextLink.crossOrigin = next.crossOrigin; else delete nextLink.crossOrigin; return nextLink; } async function transformManifestAssets(source, transformFn, _opts) { const manifest = structuredClone(source); const inlineCssEnabled = _opts?.inlineCss !== false; const scriptTransforms = /* @__PURE__ */ new Map(); const transformScript = (url) => { const cached = scriptTransforms.get(url); if (cached) return cached; const transformed = Promise.resolve(transformFn({ url, kind: "script" })).then(normalizeTransformAssetResult); scriptTransforms.set(url, transformed); return transformed; }; if (!inlineCssEnabled) delete manifest.inlineCss; else if (manifest.inlineCss) manifest.inlineCss = await transformInlineCssStyles(manifest.inlineCss, transformFn); for (const route of Object.values(manifest.routes)) { if (route.preloads?.length) route.preloads = await Promise.all(route.preloads.map(async (link) => { const result = await transformScript(resolveManifestAssetLink(link).href); return assignManifestLink(link, { href: result.href, crossOrigin: result.crossOrigin }); })); if (route.css?.length && !manifest.inlineCss) route.css = await Promise.all(route.css.map(async (link) => { const result = normalizeTransformAssetResult(await transformFn({ url: resolveManifestCssLink(link).href, kind: "stylesheet" })); return assignManifestLink(link, { href: result.href, crossOrigin: result.crossOrigin }); })); if (route.scripts?.length) for (const script of route.scripts) { const src = script.attrs?.src; if (typeof src !== "string") continue; const result = await transformScript(src); script.attrs = { ...script.attrs, src: result.href }; if (result.crossOrigin) script.attrs.crossOrigin = result.crossOrigin; else delete script.attrs.crossOrigin; } } return manifest; } /** * Builds a final ServerManifest without URL transforms. Used when no * transformAssets option is provided. * * Returns a new manifest object so the cached base manifest is never mutated. */ function buildManifest(source, opts) { return { ...source.scriptFormat ? { scriptFormat: source.scriptFormat } : {}, ...opts?.inlineCss !== false && source.inlineCss ? { inlineCss: structuredClone(source.inlineCss) } : {}, routes: { ...source.routes } }; } //#endregion export { buildManifest, resolveTransformAssetsConfig, transformManifestAssets }; //# sourceMappingURL=transformAssetUrls.js.map