@tanstack/start-server-core
Version:
Modern and scalable routing for React applications
102 lines (101 loc) • 3.38 kB
JavaScript
import { rootRouteId } from "@tanstack/router-core";
//#region src/transformAssetUrls.ts
/**
* Resolves a TransformAssetUrls value (string prefix, callback, or options
* object) into a concrete transform function and cache flag.
*/
function resolveTransformConfig(transform) {
if (typeof transform === "string") {
const prefix = transform;
return {
type: "transform",
transformFn: ({ url }) => `${prefix}${url}`,
cache: true
};
}
if (typeof transform === "function") return {
type: "transform",
transformFn: transform,
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 }) => `${transform.transform}${url}`) : transform.transform,
cache: transform.cache !== false
};
}
/**
* Builds the client entry `<script>` tag from a (possibly transformed) client
* entry URL and optional injected head scripts.
*/
function buildClientEntryScriptTag(clientEntry, injectedHeadScripts) {
let script = `import(${JSON.stringify(clientEntry)})`;
if (injectedHeadScripts) script = `${injectedHeadScripts};${script}`;
return {
tag: "script",
attrs: {
type: "module",
async: true
},
children: script
};
}
/**
* Applies a URL transform to every asset URL in the manifest and returns a
* new manifest with a client entry script tag appended to the root route's
* assets.
*
* The source manifest is deep-cloned so the cached original is never mutated.
*/
function transformManifestUrls(source, transformFn, opts) {
return (async () => {
const manifest = opts?.clone ? structuredClone(source.manifest) : source.manifest;
for (const route of Object.values(manifest.routes)) {
if (route.preloads) route.preloads = await Promise.all(route.preloads.map((url) => Promise.resolve(transformFn({
url,
type: "modulepreload"
}))));
if (route.assets) {
for (const asset of route.assets) if (asset.tag === "link" && asset.attrs?.href) asset.attrs.href = await Promise.resolve(transformFn({
url: asset.attrs.href,
type: "stylesheet"
}));
}
}
const transformedClientEntry = await Promise.resolve(transformFn({
url: source.clientEntry,
type: "clientEntry"
}));
const rootRoute = manifest.routes[rootRouteId];
if (rootRoute) {
rootRoute.assets = rootRoute.assets || [];
rootRoute.assets.push(buildClientEntryScriptTag(transformedClientEntry, source.injectedHeadScripts));
}
return manifest;
})();
}
/**
* Builds a final Manifest from a StartManifestWithClientEntry without any
* URL transforms. Used when no transformAssetUrls option is provided.
*
* Returns a new manifest object so the cached base manifest is never mutated.
*/
function buildManifestWithClientEntry(source) {
const scriptTag = buildClientEntryScriptTag(source.clientEntry, source.injectedHeadScripts);
const baseRootRoute = source.manifest.routes[rootRouteId];
return { routes: {
...source.manifest.routes,
...baseRootRoute ? { [rootRouteId]: {
...baseRootRoute,
assets: [...baseRootRoute.assets || [], scriptTag]
} } : {}
} };
}
//#endregion
export { buildManifestWithClientEntry, resolveTransformConfig, transformManifestUrls };
//# sourceMappingURL=transformAssetUrls.js.map