@teamscala/service-boot 0.23.556 → 0.23.558
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/package.json
CHANGED
|
@@ -18,6 +18,8 @@ const HYDRATE_BASE = "hydrate";
|
|
|
18
18
|
export interface HydrateBundleResult {
|
|
19
19
|
/** Served entry path (`/assets/hydrate-<hash>.js`), or null when no entry exists. */
|
|
20
20
|
hydratePath: string | null;
|
|
21
|
+
/** Chunk URLs the entry itself can load, for modulepreload emission. */
|
|
22
|
+
preloads: string[];
|
|
21
23
|
/** The VERIFIED source-map upload outcome for this build's release. */
|
|
22
24
|
sourceMaps: SourceMapUploadResult;
|
|
23
25
|
}
|
|
@@ -195,8 +197,28 @@ export async function buildHydrateBundle(
|
|
|
195
197
|
.filter((o) => o.kind === "chunk")
|
|
196
198
|
.map((o) => o.path.split("/").pop() as string),
|
|
197
199
|
);
|
|
200
|
+
const entryText = await Bun.file(hashedPath).text();
|
|
201
|
+
const preloads = [
|
|
202
|
+
...new Set(
|
|
203
|
+
[...entryText.matchAll(/["'](\/assets\/[A-Za-z0-9-]+\.js)["']/g)].map(
|
|
204
|
+
(m) => m[1],
|
|
205
|
+
),
|
|
206
|
+
),
|
|
207
|
+
].sort();
|
|
208
|
+
const unknownPreloads = preloads.filter(
|
|
209
|
+
(url) => !currentChunks.has(url.replace(/^\/assets\//, "")),
|
|
210
|
+
);
|
|
211
|
+
if (unknownPreloads.length > 0) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`[build-client-assets] entry references chunk URL(s) Bun did not emit: ${unknownPreloads.join(", ")} — refusing a manifest whose preloads name unbuilt assets`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
198
216
|
const sourceMaps = await uploadSourceMaps(cwd, outDir, hash, log, currentOutputs);
|
|
199
|
-
return {
|
|
217
|
+
return {
|
|
218
|
+
hydratePath: `${ASSET_PUBLIC_PREFIX}${hashedName}`,
|
|
219
|
+
preloads,
|
|
220
|
+
sourceMaps,
|
|
221
|
+
};
|
|
200
222
|
}
|
|
201
223
|
|
|
202
224
|
async function removeStaleChunks(
|
|
@@ -12,6 +12,7 @@ export const MANIFEST_FILE = "asset-manifest.json";
|
|
|
12
12
|
export interface AssetManifest {
|
|
13
13
|
stylesPath?: string;
|
|
14
14
|
hydratePath?: string;
|
|
15
|
+
preloads?: string[];
|
|
15
16
|
sourceMaps?: SourceMapUploadResult;
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -47,6 +48,7 @@ export async function readManifestState(outDir: string): Promise<ManifestState>
|
|
|
47
48
|
manifest: {
|
|
48
49
|
stylesPath: parsed.stylesPath,
|
|
49
50
|
hydratePath: parsed.hydratePath,
|
|
51
|
+
preloads: parsed.preloads,
|
|
50
52
|
sourceMaps: parsed.sourceMaps,
|
|
51
53
|
},
|
|
52
54
|
};
|
|
@@ -96,10 +98,12 @@ export async function verifyClientBuildAssets(
|
|
|
96
98
|
const verdict = verifyManifestState(await readManifestState(outDir), outDir);
|
|
97
99
|
if (!verdict.ok) return verdict;
|
|
98
100
|
const manifest = verdict.manifest;
|
|
99
|
-
|
|
101
|
+
const named: Array<readonly [string, string]> = [
|
|
100
102
|
["stylesheet", manifest.stylesPath],
|
|
101
103
|
["hydrate bundle", manifest.hydratePath],
|
|
102
|
-
]
|
|
104
|
+
];
|
|
105
|
+
for (const url of manifest.preloads ?? []) named.push(["preload chunk", url]);
|
|
106
|
+
for (const [label, url] of named) {
|
|
103
107
|
const file = join(outDir, url.replace(/^\/assets\//, ""));
|
|
104
108
|
if (!(await Bun.file(file).exists())) {
|
|
105
109
|
return {
|
|
@@ -11,6 +11,7 @@ import { join } from "node:path";
|
|
|
11
11
|
interface TemplateManifest {
|
|
12
12
|
stylesPath: string;
|
|
13
13
|
hydratePath: string;
|
|
14
|
+
preloads: string[];
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
const PAGE_DOCUMENT = `<!doctype html>
|
|
@@ -22,6 +23,7 @@ const PAGE_DOCUMENT = `<!doctype html>
|
|
|
22
23
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
23
24
|
<!--theme-fonts-->
|
|
24
25
|
<link rel="stylesheet" href="{{stylesPath}}" />
|
|
26
|
+
<!--module-preloads-->
|
|
25
27
|
<!--head-outlet-->
|
|
26
28
|
</head>
|
|
27
29
|
<body>
|
|
@@ -56,7 +58,11 @@ async function manifestMtimeMs(): Promise<number> {
|
|
|
56
58
|
async function loadManifest(): Promise<TemplateManifest | null> {
|
|
57
59
|
const manifest = await readManifest(join(process.cwd(), "dist", "client"));
|
|
58
60
|
if (!manifest?.stylesPath || !manifest.hydratePath) return null;
|
|
59
|
-
return {
|
|
61
|
+
return {
|
|
62
|
+
stylesPath: manifest.stylesPath,
|
|
63
|
+
hydratePath: manifest.hydratePath,
|
|
64
|
+
preloads: manifest.preloads ?? [],
|
|
65
|
+
};
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
function manifestCacheKey(): string {
|
|
@@ -78,6 +84,16 @@ export async function readHtmlTemplate(): Promise<string> {
|
|
|
78
84
|
let html = PAGE_DOCUMENT
|
|
79
85
|
.replace(/\{\{stylesPath\}\}/g, manifest.stylesPath)
|
|
80
86
|
.replace(/\{\{hydratePath\}\}/g, manifest.hydratePath)
|
|
87
|
+
.replace(
|
|
88
|
+
"<!--module-preloads-->",
|
|
89
|
+
() =>
|
|
90
|
+
manifest.preloads
|
|
91
|
+
.map(
|
|
92
|
+
(url) =>
|
|
93
|
+
`<link rel="modulepreload" href="${url}" />`,
|
|
94
|
+
)
|
|
95
|
+
.join("\n\t\t"),
|
|
96
|
+
)
|
|
81
97
|
.replace("<!--theme-fonts-->", () => themeFontsLink());
|
|
82
98
|
htmlCache.set(manifestCacheKey(), { html, manifestMtime });
|
|
83
99
|
return html;
|