Skip to content
File

Blob: src/client/server/assets.ts

typescript77 lines
1import { clientEntrypoints, type ClientEntrypoint } from "@/client/entrypoints";
2import { getClientManifest } from "./manifest";
3 
4export type DocumentAssets = {
5 styles: string[];
6 moduleScripts: string[];
7 preloads: string[];
8};
9 
10function unique(values: string[]): string[] {
11 return [...new Set(values)];
12}
13 
14function collectManifestImports(
15 manifest: Awaited<ReturnType<typeof getClientManifest>>,
16 key: string | undefined,
17 preloadSet: Set<string>
18) {
19 if (!key || preloadSet.has(key) || !manifest?.[key]) {
20 return;
21 }
22 
23 preloadSet.add(key);
24 for (const importedKey of manifest[key].imports || []) {
25 collectManifestImports(manifest, importedKey, preloadSet);
26 }
27}
28 
29export async function resolveDocumentAssets(
30 env: Env,
31 moduleEntries: ClientEntrypoint[]
32): Promise<DocumentAssets> {
33 if (import.meta.env.DEV) {
34 return {
35 styles: ["/src/client/styles.css"],
36 moduleScripts: ["/@vite/client", ...moduleEntries.map((entry) => `/${entry}`)],
37 preloads: [],
38 };
39 }
40 
41 const manifest = await getClientManifest(env);
42 const styleEntry = manifest?.[clientEntrypoints.styles];
43 const scriptEntries = moduleEntries
44 .map((entry) => manifest?.[entry])
45 .filter((entry): entry is NonNullable<typeof manifest>[string] => Boolean(entry));
46 
47 if (!styleEntry && scriptEntries.length === 0) {
48 return {
49 styles: [],
50 moduleScripts: [],
51 preloads: [],
52 };
53 }
54 
55 const preloadSet = new Set<string>();
56 for (const entry of scriptEntries) {
57 for (const importedKey of entry.imports || []) {
58 collectManifestImports(manifest, importedKey, preloadSet);
59 }
60 }
61 
62 return {
63 styles: unique(
64 [...(styleEntry?.css || []), ...scriptEntries.flatMap((entry) => entry.css || [])].map(
65 (href) => `/${href}`
66 )
67 ),
68 moduleScripts: unique(scriptEntries.map((entry) => `/${entry.file}`)),
69 preloads: unique(
70 [...preloadSet]
71 .map((key) => manifest?.[key]?.file)
72 .filter((value): value is string => Boolean(value))
73 .map((href) => `/${href}`)
74 ),
75 };
76}