@moku-labs/web 1.8.0 → 1.8.2
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/browser.d.mts +13 -0
- package/dist/browser.mjs +44 -6
- package/dist/index.cjs +65 -8
- package/dist/index.d.cts +13 -0
- package/dist/index.d.mts +13 -0
- package/dist/index.mjs +65 -8
- package/package.json +1 -1
package/dist/browser.d.mts
CHANGED
|
@@ -1157,6 +1157,19 @@ type Api$1 = {
|
|
|
1157
1157
|
url: string;
|
|
1158
1158
|
locale?: string;
|
|
1159
1159
|
}): string;
|
|
1160
|
+
/**
|
|
1161
|
+
* Resolve the FINAL document title for a route's head config — the same value `render`
|
|
1162
|
+
* emits in its `<title>` element (`titleTemplate` applied; a route-pinned `title`-keyed
|
|
1163
|
+
* element wins). Used by `spa` to sync `document.title` on client DATA-path navigation.
|
|
1164
|
+
*
|
|
1165
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
1166
|
+
* @returns The final document title string.
|
|
1167
|
+
* @example
|
|
1168
|
+
* ```ts
|
|
1169
|
+
* api.composeTitle({ title: "Page 2" }); // "Page 2 — Site"
|
|
1170
|
+
* ```
|
|
1171
|
+
*/
|
|
1172
|
+
composeTitle(head: HeadConfig | undefined): string;
|
|
1160
1173
|
};
|
|
1161
1174
|
declare namespace types_d_exports$6 {
|
|
1162
1175
|
export { COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentHooks, ComponentInstance, ExtractApi, PageData, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
|
package/dist/browser.mjs
CHANGED
|
@@ -2579,6 +2579,26 @@ function composeHead(input) {
|
|
|
2579
2579
|
}), ...head.elements ?? []]);
|
|
2580
2580
|
}
|
|
2581
2581
|
/**
|
|
2582
|
+
* Resolve the FINAL document title for a route's head config — the same value
|
|
2583
|
+
* {@link composeHead} emits in its `<title>` element. A route-supplied `title`-keyed
|
|
2584
|
+
* element wins the keyed last-wins de-dupe over the templated base title (how a route
|
|
2585
|
+
* pins a bare title past `titleTemplate`), so it must win here too; otherwise the
|
|
2586
|
+
* template is applied to `head.title ?? site.name()`. Reused by `spa` for the client
|
|
2587
|
+
* DATA-path `document.title` sync, so client-side navigation matches the SSG output.
|
|
2588
|
+
*
|
|
2589
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
2590
|
+
* @param defaults - The normalized head defaults (provides `titleTemplate`).
|
|
2591
|
+
* @param site - The site slice (title fallback).
|
|
2592
|
+
* @returns The final document title string.
|
|
2593
|
+
* @example composeTitle({ title: "Page 2" }, defaults, site) // "Page 2 — Site"
|
|
2594
|
+
*/
|
|
2595
|
+
function composeTitle(head, defaults, site) {
|
|
2596
|
+
const config = head ?? {};
|
|
2597
|
+
const pinned = config.elements?.findLast((element) => element.key === "title");
|
|
2598
|
+
if (pinned?.children !== void 0) return pinned.children;
|
|
2599
|
+
return applyTemplate(config.title ?? site.name(), defaults.titleTemplate);
|
|
2600
|
+
}
|
|
2601
|
+
/**
|
|
2582
2602
|
* Compose the SITE-LEVEL Open Graph / Twitter block for a bare-path redirect or landing
|
|
2583
2603
|
* page that has no per-route head of its own. Returns `[]` UNLESS a `defaultOgImage` is
|
|
2584
2604
|
* configured — so apps that opt out keep a bare redirect (no behavior change). The site
|
|
@@ -2748,6 +2768,21 @@ function createApi$1(ctx) {
|
|
|
2748
2768
|
url: site.canonical(input.url),
|
|
2749
2769
|
...ogLocale === void 0 ? {} : { ogLocale }
|
|
2750
2770
|
}));
|
|
2771
|
+
},
|
|
2772
|
+
/**
|
|
2773
|
+
* Resolve the FINAL document title for a route's head config — the same value `render`
|
|
2774
|
+
* emits in its `<title>` element. Pulled by `spa` on the client DATA path so a
|
|
2775
|
+
* client-side navigation's `document.title` matches the SSG output.
|
|
2776
|
+
*
|
|
2777
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
2778
|
+
* @returns The final document title string.
|
|
2779
|
+
* @example
|
|
2780
|
+
* ```ts
|
|
2781
|
+
* api.composeTitle({ title: "Page 2" }); // "Page 2 — Site"
|
|
2782
|
+
* ```
|
|
2783
|
+
*/
|
|
2784
|
+
composeTitle(head) {
|
|
2785
|
+
return composeTitle(head, readDefaults(ctx.state), ctx.require(sitePlugin));
|
|
2751
2786
|
}
|
|
2752
2787
|
};
|
|
2753
2788
|
}
|
|
@@ -4020,16 +4055,19 @@ function currentLocationUrl() {
|
|
|
4020
4055
|
/**
|
|
4021
4056
|
* Apply the matched route's `head` config to the live document (minimal client
|
|
4022
4057
|
* head-sync for the DATA path: title only — the full meta sync runs on the
|
|
4023
|
-
* HTML-over-fetch path from the fetched `<head>`).
|
|
4058
|
+
* HTML-over-fetch path from the fetched `<head>`). The title is resolved through
|
|
4059
|
+
* `head.composeTitle` — the SAME composition `render` uses (`titleTemplate` applied;
|
|
4060
|
+
* a route-pinned `title` element wins) — so a client-side navigation's
|
|
4061
|
+
* `document.title` matches the SSG output instead of the raw route title.
|
|
4024
4062
|
*
|
|
4063
|
+
* @param head - The head plugin API (resolves the final templated title).
|
|
4025
4064
|
* @param route - The matched route definition.
|
|
4026
4065
|
* @param routeContext - The render context (params/data/locale).
|
|
4027
4066
|
* @example
|
|
4028
|
-
* syncDataHead(hit.route, { params, data, locale });
|
|
4067
|
+
* syncDataHead(deps.head, hit.route, { params, data, locale });
|
|
4029
4068
|
*/
|
|
4030
|
-
function syncDataHead(route, routeContext) {
|
|
4031
|
-
|
|
4032
|
-
if (title !== void 0 && title !== "") document.title = title;
|
|
4069
|
+
function syncDataHead(head, route, routeContext) {
|
|
4070
|
+
document.title = head.composeTitle(route._handlers.head?.(routeContext));
|
|
4033
4071
|
}
|
|
4034
4072
|
/**
|
|
4035
4073
|
* Builds the single shared SPA kernel — a pure factory over state/config/emit.
|
|
@@ -4185,7 +4223,7 @@ function createSpaKernel(state, config, emit, deps) {
|
|
|
4185
4223
|
handleStart(pathname);
|
|
4186
4224
|
const { renderVNode } = await import("./render-BNe0s7fr.mjs");
|
|
4187
4225
|
if (signal?.aborted) return;
|
|
4188
|
-
syncDataHead(route, routeContext);
|
|
4226
|
+
syncDataHead(deps.head, route, routeContext);
|
|
4189
4227
|
unmountPageSpecific(state, emit);
|
|
4190
4228
|
/**
|
|
4191
4229
|
* Render the VNode into the region and re-mount its islands in one paint — the
|
package/dist/index.cjs
CHANGED
|
@@ -3169,6 +3169,26 @@ function composeHead(input) {
|
|
|
3169
3169
|
}), ...head.elements ?? []]);
|
|
3170
3170
|
}
|
|
3171
3171
|
/**
|
|
3172
|
+
* Resolve the FINAL document title for a route's head config — the same value
|
|
3173
|
+
* {@link composeHead} emits in its `<title>` element. A route-supplied `title`-keyed
|
|
3174
|
+
* element wins the keyed last-wins de-dupe over the templated base title (how a route
|
|
3175
|
+
* pins a bare title past `titleTemplate`), so it must win here too; otherwise the
|
|
3176
|
+
* template is applied to `head.title ?? site.name()`. Reused by `spa` for the client
|
|
3177
|
+
* DATA-path `document.title` sync, so client-side navigation matches the SSG output.
|
|
3178
|
+
*
|
|
3179
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
3180
|
+
* @param defaults - The normalized head defaults (provides `titleTemplate`).
|
|
3181
|
+
* @param site - The site slice (title fallback).
|
|
3182
|
+
* @returns The final document title string.
|
|
3183
|
+
* @example composeTitle({ title: "Page 2" }, defaults, site) // "Page 2 — Site"
|
|
3184
|
+
*/
|
|
3185
|
+
function composeTitle(head, defaults, site) {
|
|
3186
|
+
const config = head ?? {};
|
|
3187
|
+
const pinned = config.elements?.findLast((element) => element.key === "title");
|
|
3188
|
+
if (pinned?.children !== void 0) return pinned.children;
|
|
3189
|
+
return applyTemplate(config.title ?? site.name(), defaults.titleTemplate);
|
|
3190
|
+
}
|
|
3191
|
+
/**
|
|
3172
3192
|
* Compose the SITE-LEVEL Open Graph / Twitter block for a bare-path redirect or landing
|
|
3173
3193
|
* page that has no per-route head of its own. Returns `[]` UNLESS a `defaultOgImage` is
|
|
3174
3194
|
* configured — so apps that opt out keep a bare redirect (no behavior change). The site
|
|
@@ -3338,6 +3358,21 @@ function createApi$4(ctx) {
|
|
|
3338
3358
|
url: site.canonical(input.url),
|
|
3339
3359
|
...ogLocale === void 0 ? {} : { ogLocale }
|
|
3340
3360
|
}));
|
|
3361
|
+
},
|
|
3362
|
+
/**
|
|
3363
|
+
* Resolve the FINAL document title for a route's head config — the same value `render`
|
|
3364
|
+
* emits in its `<title>` element. Pulled by `spa` on the client DATA path so a
|
|
3365
|
+
* client-side navigation's `document.title` matches the SSG output.
|
|
3366
|
+
*
|
|
3367
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
3368
|
+
* @returns The final document title string.
|
|
3369
|
+
* @example
|
|
3370
|
+
* ```ts
|
|
3371
|
+
* api.composeTitle({ title: "Page 2" }); // "Page 2 — Site"
|
|
3372
|
+
* ```
|
|
3373
|
+
*/
|
|
3374
|
+
composeTitle(head) {
|
|
3375
|
+
return composeTitle(head, readDefaults(ctx.state), ctx.require(sitePlugin));
|
|
3341
3376
|
}
|
|
3342
3377
|
};
|
|
3343
3378
|
}
|
|
@@ -3515,6 +3550,23 @@ const FINGERPRINT_NAMING = {
|
|
|
3515
3550
|
asset: "[name]-[hash].[ext]"
|
|
3516
3551
|
};
|
|
3517
3552
|
/**
|
|
3553
|
+
* Font url() references the CSS pass leaves EXTERNAL instead of bundling.
|
|
3554
|
+
* Bun's CSS bundler cannot emit url() assets as files — every resolvable
|
|
3555
|
+
* font reference is inlined as a base64 data URI, ballooning the stylesheet
|
|
3556
|
+
* (a site vendoring a font family ships every weight/subset render-blocking
|
|
3557
|
+
* on every page). Marking font extensions external passes the URL through
|
|
3558
|
+
* verbatim, so apps reference fonts root-relative (e.g. `/fonts/x.woff2`)
|
|
3559
|
+
* and serve the files statically via `publicDir`. CSS-only: a font import
|
|
3560
|
+
* left external in JS would be an unresolvable module at runtime.
|
|
3561
|
+
*/
|
|
3562
|
+
const CSS_EXTERNAL_FONT_GLOBS = [
|
|
3563
|
+
"*.woff2",
|
|
3564
|
+
"*.woff",
|
|
3565
|
+
"*.ttf",
|
|
3566
|
+
"*.otf",
|
|
3567
|
+
"*.eot"
|
|
3568
|
+
];
|
|
3569
|
+
/**
|
|
3518
3570
|
* The default bundler runner — adapts the built-in `Bun.build`.
|
|
3519
3571
|
*
|
|
3520
3572
|
* @param options - Entry/outdir/minify/splitting/target/naming settings forwarded to `Bun.build`.
|
|
@@ -3527,10 +3579,11 @@ const FINGERPRINT_NAMING = {
|
|
|
3527
3579
|
* @param options.naming.entry - Naming template for entry-point outputs.
|
|
3528
3580
|
* @param options.naming.chunk - Naming template for lazy split chunks.
|
|
3529
3581
|
* @param options.naming.asset - Naming template for additional emitted assets.
|
|
3582
|
+
* @param options.external - Import/url() globs left unresolved in the output.
|
|
3530
3583
|
* @returns The structural build result.
|
|
3531
3584
|
* @example
|
|
3532
3585
|
* ```ts
|
|
3533
|
-
* await defaultRunner({ entrypoints: ["a.css"], outdir: "dist", minify: true, splitting: true, target: "browser", naming: FINGERPRINT_NAMING });
|
|
3586
|
+
* await defaultRunner({ entrypoints: ["a.css"], outdir: "dist", minify: true, splitting: true, target: "browser", naming: FINGERPRINT_NAMING, external: [] });
|
|
3534
3587
|
* ```
|
|
3535
3588
|
*/
|
|
3536
3589
|
async function defaultRunner(options) {
|
|
@@ -3623,7 +3676,8 @@ async function runOne(ctx, runner, kind, entrypoints, outDir, outdir, minify) {
|
|
|
3623
3676
|
minify,
|
|
3624
3677
|
splitting: true,
|
|
3625
3678
|
target: "browser",
|
|
3626
|
-
naming: FINGERPRINT_NAMING
|
|
3679
|
+
naming: FINGERPRINT_NAMING,
|
|
3680
|
+
external: kind === "css" ? [...CSS_EXTERNAL_FONT_GLOBS] : []
|
|
3627
3681
|
});
|
|
3628
3682
|
if (!result.success) throw new Error(`[web] build.bundle ${kind} build failed`);
|
|
3629
3683
|
const hashed = {};
|
|
@@ -10868,16 +10922,19 @@ function currentLocationUrl() {
|
|
|
10868
10922
|
/**
|
|
10869
10923
|
* Apply the matched route's `head` config to the live document (minimal client
|
|
10870
10924
|
* head-sync for the DATA path: title only — the full meta sync runs on the
|
|
10871
|
-
* HTML-over-fetch path from the fetched `<head>`).
|
|
10925
|
+
* HTML-over-fetch path from the fetched `<head>`). The title is resolved through
|
|
10926
|
+
* `head.composeTitle` — the SAME composition `render` uses (`titleTemplate` applied;
|
|
10927
|
+
* a route-pinned `title` element wins) — so a client-side navigation's
|
|
10928
|
+
* `document.title` matches the SSG output instead of the raw route title.
|
|
10872
10929
|
*
|
|
10930
|
+
* @param head - The head plugin API (resolves the final templated title).
|
|
10873
10931
|
* @param route - The matched route definition.
|
|
10874
10932
|
* @param routeContext - The render context (params/data/locale).
|
|
10875
10933
|
* @example
|
|
10876
|
-
* syncDataHead(hit.route, { params, data, locale });
|
|
10934
|
+
* syncDataHead(deps.head, hit.route, { params, data, locale });
|
|
10877
10935
|
*/
|
|
10878
|
-
function syncDataHead(route, routeContext) {
|
|
10879
|
-
|
|
10880
|
-
if (title !== void 0 && title !== "") document.title = title;
|
|
10936
|
+
function syncDataHead(head, route, routeContext) {
|
|
10937
|
+
document.title = head.composeTitle(route._handlers.head?.(routeContext));
|
|
10881
10938
|
}
|
|
10882
10939
|
/**
|
|
10883
10940
|
* Builds the single shared SPA kernel — a pure factory over state/config/emit.
|
|
@@ -11033,7 +11090,7 @@ function createSpaKernel(state, config, emit, deps) {
|
|
|
11033
11090
|
handleStart(pathname);
|
|
11034
11091
|
const { renderVNode } = await Promise.resolve().then(() => require("./render-DLZEOe4M.cjs"));
|
|
11035
11092
|
if (signal?.aborted) return;
|
|
11036
|
-
syncDataHead(route, routeContext);
|
|
11093
|
+
syncDataHead(deps.head, route, routeContext);
|
|
11037
11094
|
unmountPageSpecific(state, emit);
|
|
11038
11095
|
/**
|
|
11039
11096
|
* Render the VNode into the region and re-mount its islands in one paint — the
|
package/dist/index.d.cts
CHANGED
|
@@ -1157,6 +1157,19 @@ type Api$4 = {
|
|
|
1157
1157
|
url: string;
|
|
1158
1158
|
locale?: string;
|
|
1159
1159
|
}): string;
|
|
1160
|
+
/**
|
|
1161
|
+
* Resolve the FINAL document title for a route's head config — the same value `render`
|
|
1162
|
+
* emits in its `<title>` element (`titleTemplate` applied; a route-pinned `title`-keyed
|
|
1163
|
+
* element wins). Used by `spa` to sync `document.title` on client DATA-path navigation.
|
|
1164
|
+
*
|
|
1165
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
1166
|
+
* @returns The final document title string.
|
|
1167
|
+
* @example
|
|
1168
|
+
* ```ts
|
|
1169
|
+
* api.composeTitle({ title: "Page 2" }); // "Page 2 — Site"
|
|
1170
|
+
* ```
|
|
1171
|
+
*/
|
|
1172
|
+
composeTitle(head: HeadConfig | undefined): string;
|
|
1160
1173
|
};
|
|
1161
1174
|
declare namespace types_d_exports$9 {
|
|
1162
1175
|
export { COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentHooks, ComponentInstance, ExtractApi$1 as ExtractApi, PageData, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
|
package/dist/index.d.mts
CHANGED
|
@@ -1157,6 +1157,19 @@ type Api$4 = {
|
|
|
1157
1157
|
url: string;
|
|
1158
1158
|
locale?: string;
|
|
1159
1159
|
}): string;
|
|
1160
|
+
/**
|
|
1161
|
+
* Resolve the FINAL document title for a route's head config — the same value `render`
|
|
1162
|
+
* emits in its `<title>` element (`titleTemplate` applied; a route-pinned `title`-keyed
|
|
1163
|
+
* element wins). Used by `spa` to sync `document.title` on client DATA-path navigation.
|
|
1164
|
+
*
|
|
1165
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
1166
|
+
* @returns The final document title string.
|
|
1167
|
+
* @example
|
|
1168
|
+
* ```ts
|
|
1169
|
+
* api.composeTitle({ title: "Page 2" }); // "Page 2 — Site"
|
|
1170
|
+
* ```
|
|
1171
|
+
*/
|
|
1172
|
+
composeTitle(head: HeadConfig | undefined): string;
|
|
1160
1173
|
};
|
|
1161
1174
|
declare namespace types_d_exports$9 {
|
|
1162
1175
|
export { COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentHooks, ComponentInstance, ExtractApi$1 as ExtractApi, PageData, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
|
package/dist/index.mjs
CHANGED
|
@@ -3156,6 +3156,26 @@ function composeHead(input) {
|
|
|
3156
3156
|
}), ...head.elements ?? []]);
|
|
3157
3157
|
}
|
|
3158
3158
|
/**
|
|
3159
|
+
* Resolve the FINAL document title for a route's head config — the same value
|
|
3160
|
+
* {@link composeHead} emits in its `<title>` element. A route-supplied `title`-keyed
|
|
3161
|
+
* element wins the keyed last-wins de-dupe over the templated base title (how a route
|
|
3162
|
+
* pins a bare title past `titleTemplate`), so it must win here too; otherwise the
|
|
3163
|
+
* template is applied to `head.title ?? site.name()`. Reused by `spa` for the client
|
|
3164
|
+
* DATA-path `document.title` sync, so client-side navigation matches the SSG output.
|
|
3165
|
+
*
|
|
3166
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
3167
|
+
* @param defaults - The normalized head defaults (provides `titleTemplate`).
|
|
3168
|
+
* @param site - The site slice (title fallback).
|
|
3169
|
+
* @returns The final document title string.
|
|
3170
|
+
* @example composeTitle({ title: "Page 2" }, defaults, site) // "Page 2 — Site"
|
|
3171
|
+
*/
|
|
3172
|
+
function composeTitle(head, defaults, site) {
|
|
3173
|
+
const config = head ?? {};
|
|
3174
|
+
const pinned = config.elements?.findLast((element) => element.key === "title");
|
|
3175
|
+
if (pinned?.children !== void 0) return pinned.children;
|
|
3176
|
+
return applyTemplate(config.title ?? site.name(), defaults.titleTemplate);
|
|
3177
|
+
}
|
|
3178
|
+
/**
|
|
3159
3179
|
* Compose the SITE-LEVEL Open Graph / Twitter block for a bare-path redirect or landing
|
|
3160
3180
|
* page that has no per-route head of its own. Returns `[]` UNLESS a `defaultOgImage` is
|
|
3161
3181
|
* configured — so apps that opt out keep a bare redirect (no behavior change). The site
|
|
@@ -3325,6 +3345,21 @@ function createApi$4(ctx) {
|
|
|
3325
3345
|
url: site.canonical(input.url),
|
|
3326
3346
|
...ogLocale === void 0 ? {} : { ogLocale }
|
|
3327
3347
|
}));
|
|
3348
|
+
},
|
|
3349
|
+
/**
|
|
3350
|
+
* Resolve the FINAL document title for a route's head config — the same value `render`
|
|
3351
|
+
* emits in its `<title>` element. Pulled by `spa` on the client DATA path so a
|
|
3352
|
+
* client-side navigation's `document.title` matches the SSG output.
|
|
3353
|
+
*
|
|
3354
|
+
* @param head - The route's head config (may be `undefined` for head-less routes).
|
|
3355
|
+
* @returns The final document title string.
|
|
3356
|
+
* @example
|
|
3357
|
+
* ```ts
|
|
3358
|
+
* api.composeTitle({ title: "Page 2" }); // "Page 2 — Site"
|
|
3359
|
+
* ```
|
|
3360
|
+
*/
|
|
3361
|
+
composeTitle(head) {
|
|
3362
|
+
return composeTitle(head, readDefaults(ctx.state), ctx.require(sitePlugin));
|
|
3328
3363
|
}
|
|
3329
3364
|
};
|
|
3330
3365
|
}
|
|
@@ -3502,6 +3537,23 @@ const FINGERPRINT_NAMING = {
|
|
|
3502
3537
|
asset: "[name]-[hash].[ext]"
|
|
3503
3538
|
};
|
|
3504
3539
|
/**
|
|
3540
|
+
* Font url() references the CSS pass leaves EXTERNAL instead of bundling.
|
|
3541
|
+
* Bun's CSS bundler cannot emit url() assets as files — every resolvable
|
|
3542
|
+
* font reference is inlined as a base64 data URI, ballooning the stylesheet
|
|
3543
|
+
* (a site vendoring a font family ships every weight/subset render-blocking
|
|
3544
|
+
* on every page). Marking font extensions external passes the URL through
|
|
3545
|
+
* verbatim, so apps reference fonts root-relative (e.g. `/fonts/x.woff2`)
|
|
3546
|
+
* and serve the files statically via `publicDir`. CSS-only: a font import
|
|
3547
|
+
* left external in JS would be an unresolvable module at runtime.
|
|
3548
|
+
*/
|
|
3549
|
+
const CSS_EXTERNAL_FONT_GLOBS = [
|
|
3550
|
+
"*.woff2",
|
|
3551
|
+
"*.woff",
|
|
3552
|
+
"*.ttf",
|
|
3553
|
+
"*.otf",
|
|
3554
|
+
"*.eot"
|
|
3555
|
+
];
|
|
3556
|
+
/**
|
|
3505
3557
|
* The default bundler runner — adapts the built-in `Bun.build`.
|
|
3506
3558
|
*
|
|
3507
3559
|
* @param options - Entry/outdir/minify/splitting/target/naming settings forwarded to `Bun.build`.
|
|
@@ -3514,10 +3566,11 @@ const FINGERPRINT_NAMING = {
|
|
|
3514
3566
|
* @param options.naming.entry - Naming template for entry-point outputs.
|
|
3515
3567
|
* @param options.naming.chunk - Naming template for lazy split chunks.
|
|
3516
3568
|
* @param options.naming.asset - Naming template for additional emitted assets.
|
|
3569
|
+
* @param options.external - Import/url() globs left unresolved in the output.
|
|
3517
3570
|
* @returns The structural build result.
|
|
3518
3571
|
* @example
|
|
3519
3572
|
* ```ts
|
|
3520
|
-
* await defaultRunner({ entrypoints: ["a.css"], outdir: "dist", minify: true, splitting: true, target: "browser", naming: FINGERPRINT_NAMING });
|
|
3573
|
+
* await defaultRunner({ entrypoints: ["a.css"], outdir: "dist", minify: true, splitting: true, target: "browser", naming: FINGERPRINT_NAMING, external: [] });
|
|
3521
3574
|
* ```
|
|
3522
3575
|
*/
|
|
3523
3576
|
async function defaultRunner(options) {
|
|
@@ -3610,7 +3663,8 @@ async function runOne(ctx, runner, kind, entrypoints, outDir, outdir, minify) {
|
|
|
3610
3663
|
minify,
|
|
3611
3664
|
splitting: true,
|
|
3612
3665
|
target: "browser",
|
|
3613
|
-
naming: FINGERPRINT_NAMING
|
|
3666
|
+
naming: FINGERPRINT_NAMING,
|
|
3667
|
+
external: kind === "css" ? [...CSS_EXTERNAL_FONT_GLOBS] : []
|
|
3614
3668
|
});
|
|
3615
3669
|
if (!result.success) throw new Error(`[web] build.bundle ${kind} build failed`);
|
|
3616
3670
|
const hashed = {};
|
|
@@ -10855,16 +10909,19 @@ function currentLocationUrl() {
|
|
|
10855
10909
|
/**
|
|
10856
10910
|
* Apply the matched route's `head` config to the live document (minimal client
|
|
10857
10911
|
* head-sync for the DATA path: title only — the full meta sync runs on the
|
|
10858
|
-
* HTML-over-fetch path from the fetched `<head>`).
|
|
10912
|
+
* HTML-over-fetch path from the fetched `<head>`). The title is resolved through
|
|
10913
|
+
* `head.composeTitle` — the SAME composition `render` uses (`titleTemplate` applied;
|
|
10914
|
+
* a route-pinned `title` element wins) — so a client-side navigation's
|
|
10915
|
+
* `document.title` matches the SSG output instead of the raw route title.
|
|
10859
10916
|
*
|
|
10917
|
+
* @param head - The head plugin API (resolves the final templated title).
|
|
10860
10918
|
* @param route - The matched route definition.
|
|
10861
10919
|
* @param routeContext - The render context (params/data/locale).
|
|
10862
10920
|
* @example
|
|
10863
|
-
* syncDataHead(hit.route, { params, data, locale });
|
|
10921
|
+
* syncDataHead(deps.head, hit.route, { params, data, locale });
|
|
10864
10922
|
*/
|
|
10865
|
-
function syncDataHead(route, routeContext) {
|
|
10866
|
-
|
|
10867
|
-
if (title !== void 0 && title !== "") document.title = title;
|
|
10923
|
+
function syncDataHead(head, route, routeContext) {
|
|
10924
|
+
document.title = head.composeTitle(route._handlers.head?.(routeContext));
|
|
10868
10925
|
}
|
|
10869
10926
|
/**
|
|
10870
10927
|
* Builds the single shared SPA kernel — a pure factory over state/config/emit.
|
|
@@ -11020,7 +11077,7 @@ function createSpaKernel(state, config, emit, deps) {
|
|
|
11020
11077
|
handleStart(pathname);
|
|
11021
11078
|
const { renderVNode } = await import("./render-BNe0s7fr.mjs");
|
|
11022
11079
|
if (signal?.aborted) return;
|
|
11023
|
-
syncDataHead(route, routeContext);
|
|
11080
|
+
syncDataHead(deps.head, route, routeContext);
|
|
11024
11081
|
unmountPageSpecific(state, emit);
|
|
11025
11082
|
/**
|
|
11026
11083
|
* Render the VNode into the region and re-mount its islands in one paint — the
|
package/package.json
CHANGED