@moku-labs/web 1.5.1 → 1.5.3
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/index.cjs +29 -7
- package/dist/index.d.cts +18 -8
- package/dist/index.d.mts +18 -8
- package/dist/index.mjs +29 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3992,10 +3992,31 @@ function wrap(body) {
|
|
|
3992
3992
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>404 — Not Found</title></head><body>${body}</body></html>`;
|
|
3993
3993
|
}
|
|
3994
3994
|
/**
|
|
3995
|
+
* Resolve the 404 page HTML from `config.notFound`. Precedence: `path` (a
|
|
3996
|
+
* complete page file, read verbatim) > `body` (a fragment, wrapped in the
|
|
3997
|
+
* minimal shell) > the built-in default.
|
|
3998
|
+
*
|
|
3999
|
+
* @param notFound - The `config.notFound` value (already known to be truthy).
|
|
4000
|
+
* @returns The complete HTML document to write.
|
|
4001
|
+
* @example
|
|
4002
|
+
* ```ts
|
|
4003
|
+
* const html = await resolveHtml({ path: "src/404.html" });
|
|
4004
|
+
* ```
|
|
4005
|
+
*/
|
|
4006
|
+
async function resolveHtml(notFound) {
|
|
4007
|
+
if (typeof notFound === "object" && notFound.path) try {
|
|
4008
|
+
return await (0, node_fs_promises.readFile)(notFound.path, "utf8");
|
|
4009
|
+
} catch (error) {
|
|
4010
|
+
throw new Error(`build:not-found — could not read notFound.path "${notFound.path}"`, { cause: error });
|
|
4011
|
+
}
|
|
4012
|
+
return wrap(typeof notFound === "object" && notFound.body ? notFound.body : DEFAULT_BODY);
|
|
4013
|
+
}
|
|
4014
|
+
/**
|
|
3995
4015
|
* Emits `outDir/404.html`. When `config.notFound` is `true`, writes the built-in
|
|
3996
|
-
* default page;
|
|
3997
|
-
*
|
|
3998
|
-
*
|
|
4016
|
+
* default page; `{ body }` writes the supplied HTML body content inside the
|
|
4017
|
+
* minimal document shell; `{ path }` writes the referenced HTML page file
|
|
4018
|
+
* verbatim (the app owns the whole document). No-op (returns `null`) when
|
|
4019
|
+
* `notFound` is false/unset.
|
|
3999
4020
|
*
|
|
4000
4021
|
* @param ctx - Plugin context (provides `config`, `log`).
|
|
4001
4022
|
* @returns The written file path, or `null` when disabled.
|
|
@@ -4010,10 +4031,10 @@ async function generateNotFound(ctx) {
|
|
|
4010
4031
|
ctx.log.debug("build:not-found", { skipped: true });
|
|
4011
4032
|
return null;
|
|
4012
4033
|
}
|
|
4013
|
-
const
|
|
4034
|
+
const html = await resolveHtml(notFound);
|
|
4014
4035
|
await (0, node_fs_promises.mkdir)(outDir, { recursive: true });
|
|
4015
4036
|
const file = node_path$1.default.join(outDir, "404.html");
|
|
4016
|
-
await (0, node_fs_promises.writeFile)(file,
|
|
4037
|
+
await (0, node_fs_promises.writeFile)(file, html, "utf8");
|
|
4017
4038
|
ctx.log.debug("build:not-found", { path: file });
|
|
4018
4039
|
return { path: file };
|
|
4019
4040
|
}
|
|
@@ -4390,9 +4411,10 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
4390
4411
|
fonts,
|
|
4391
4412
|
...renderHook
|
|
4392
4413
|
});
|
|
4414
|
+
const siteCardRender = typeof config.defaultCard === "function" ? config.defaultCard : defaultSiteCard;
|
|
4393
4415
|
const renderSitePng = options.renderPng ?? makeDefaultRenderer({
|
|
4394
4416
|
fonts,
|
|
4395
|
-
render:
|
|
4417
|
+
render: siteCardRender
|
|
4396
4418
|
});
|
|
4397
4419
|
const siteName = resolveSiteName(ctx);
|
|
4398
4420
|
const defaultLocale = ctx.require(i18nPlugin).defaultLocale();
|
|
@@ -4418,7 +4440,7 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
4418
4440
|
outDir
|
|
4419
4441
|
}, tally);
|
|
4420
4442
|
})));
|
|
4421
|
-
const defaultCard = config.defaultCard === true;
|
|
4443
|
+
const defaultCard = config.defaultCard === true || typeof config.defaultCard === "function";
|
|
4422
4444
|
if (defaultCard) {
|
|
4423
4445
|
const png = await renderSitePng({
|
|
4424
4446
|
title: siteName,
|
package/dist/index.d.cts
CHANGED
|
@@ -1633,12 +1633,16 @@ interface OgImageConfig {
|
|
|
1633
1633
|
/** Explicit named fonts loaded once per build (overrides the first-file scan). */
|
|
1634
1634
|
fonts?: OgFont[];
|
|
1635
1635
|
/**
|
|
1636
|
-
*
|
|
1637
|
-
*
|
|
1638
|
-
* per-article `render` hook is NOT applied
|
|
1639
|
-
*
|
|
1636
|
+
* Also render a single SITE-LEVEL default card to `<outDir>/og-default.png`, used (via
|
|
1637
|
+
* `head.defaultOgImage: "/og-default.png"`) as the og:image fallback for non-article pages.
|
|
1638
|
+
* Rendered ONCE with the same loaded fonts; the per-article `render` hook is NOT applied.
|
|
1639
|
+
*
|
|
1640
|
+
* - `true` → the built-in generic card (site name over its description on a dark background).
|
|
1641
|
+
* - a render function → your OWN card, e.g. `defaultCard: MySiteCard` (a `(input) => VNode`,
|
|
1642
|
+
* the same shape as `render`); `input.siteName`/`input.description` carry the site identity.
|
|
1643
|
+
* - `false`/omitted → no card (default).
|
|
1640
1644
|
*/
|
|
1641
|
-
defaultCard?: boolean;
|
|
1645
|
+
defaultCard?: boolean | ((input: RichOgInput) => import("preact").VNode);
|
|
1642
1646
|
}
|
|
1643
1647
|
/**
|
|
1644
1648
|
* Public configuration for the `build` plugin. Flags give opt-in granularity over
|
|
@@ -1659,12 +1663,18 @@ type Config$3 = {
|
|
|
1659
1663
|
injectAssets?: boolean; /** Directory copied verbatim into `outDir` (skipped silently if absent). Default `"public"`. */
|
|
1660
1664
|
publicDir?: string;
|
|
1661
1665
|
/**
|
|
1662
|
-
* Emit `outDir/404.html`.
|
|
1663
|
-
*
|
|
1664
|
-
*
|
|
1666
|
+
* Emit `outDir/404.html`. One of:
|
|
1667
|
+
* - `true` — the built-in default page.
|
|
1668
|
+
* - `{ body }` — literal HTML body content, wrapped in a minimal document shell.
|
|
1669
|
+
* - `{ path }` — path to a complete HTML page file (resolved from the project
|
|
1670
|
+
* root), written out VERBATIM so the app owns the whole document (its own
|
|
1671
|
+
* `<head>`, asset links, and body).
|
|
1672
|
+
*
|
|
1673
|
+
* `path` takes precedence over `body` when both are set. Default `false`.
|
|
1665
1674
|
*/
|
|
1666
1675
|
notFound?: boolean | {
|
|
1667
1676
|
body?: string;
|
|
1677
|
+
path?: string;
|
|
1668
1678
|
}; /** Emit per-path i18n bare-path redirect HTML pages. Default `false`. */
|
|
1669
1679
|
localeRedirects?: boolean; /** Authoritative client bundle entry path (overrides the conventional scan). */
|
|
1670
1680
|
clientEntry?: string;
|
package/dist/index.d.mts
CHANGED
|
@@ -1633,12 +1633,16 @@ interface OgImageConfig {
|
|
|
1633
1633
|
/** Explicit named fonts loaded once per build (overrides the first-file scan). */
|
|
1634
1634
|
fonts?: OgFont[];
|
|
1635
1635
|
/**
|
|
1636
|
-
*
|
|
1637
|
-
*
|
|
1638
|
-
* per-article `render` hook is NOT applied
|
|
1639
|
-
*
|
|
1636
|
+
* Also render a single SITE-LEVEL default card to `<outDir>/og-default.png`, used (via
|
|
1637
|
+
* `head.defaultOgImage: "/og-default.png"`) as the og:image fallback for non-article pages.
|
|
1638
|
+
* Rendered ONCE with the same loaded fonts; the per-article `render` hook is NOT applied.
|
|
1639
|
+
*
|
|
1640
|
+
* - `true` → the built-in generic card (site name over its description on a dark background).
|
|
1641
|
+
* - a render function → your OWN card, e.g. `defaultCard: MySiteCard` (a `(input) => VNode`,
|
|
1642
|
+
* the same shape as `render`); `input.siteName`/`input.description` carry the site identity.
|
|
1643
|
+
* - `false`/omitted → no card (default).
|
|
1640
1644
|
*/
|
|
1641
|
-
defaultCard?: boolean;
|
|
1645
|
+
defaultCard?: boolean | ((input: RichOgInput) => import("preact").VNode);
|
|
1642
1646
|
}
|
|
1643
1647
|
/**
|
|
1644
1648
|
* Public configuration for the `build` plugin. Flags give opt-in granularity over
|
|
@@ -1659,12 +1663,18 @@ type Config$3 = {
|
|
|
1659
1663
|
injectAssets?: boolean; /** Directory copied verbatim into `outDir` (skipped silently if absent). Default `"public"`. */
|
|
1660
1664
|
publicDir?: string;
|
|
1661
1665
|
/**
|
|
1662
|
-
* Emit `outDir/404.html`.
|
|
1663
|
-
*
|
|
1664
|
-
*
|
|
1666
|
+
* Emit `outDir/404.html`. One of:
|
|
1667
|
+
* - `true` — the built-in default page.
|
|
1668
|
+
* - `{ body }` — literal HTML body content, wrapped in a minimal document shell.
|
|
1669
|
+
* - `{ path }` — path to a complete HTML page file (resolved from the project
|
|
1670
|
+
* root), written out VERBATIM so the app owns the whole document (its own
|
|
1671
|
+
* `<head>`, asset links, and body).
|
|
1672
|
+
*
|
|
1673
|
+
* `path` takes precedence over `body` when both are set. Default `false`.
|
|
1665
1674
|
*/
|
|
1666
1675
|
notFound?: boolean | {
|
|
1667
1676
|
body?: string;
|
|
1677
|
+
path?: string;
|
|
1668
1678
|
}; /** Emit per-path i18n bare-path redirect HTML pages. Default `false`. */
|
|
1669
1679
|
localeRedirects?: boolean; /** Authoritative client bundle entry path (overrides the conventional scan). */
|
|
1670
1680
|
clientEntry?: string;
|
package/dist/index.mjs
CHANGED
|
@@ -3979,10 +3979,31 @@ function wrap(body) {
|
|
|
3979
3979
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>404 — Not Found</title></head><body>${body}</body></html>`;
|
|
3980
3980
|
}
|
|
3981
3981
|
/**
|
|
3982
|
+
* Resolve the 404 page HTML from `config.notFound`. Precedence: `path` (a
|
|
3983
|
+
* complete page file, read verbatim) > `body` (a fragment, wrapped in the
|
|
3984
|
+
* minimal shell) > the built-in default.
|
|
3985
|
+
*
|
|
3986
|
+
* @param notFound - The `config.notFound` value (already known to be truthy).
|
|
3987
|
+
* @returns The complete HTML document to write.
|
|
3988
|
+
* @example
|
|
3989
|
+
* ```ts
|
|
3990
|
+
* const html = await resolveHtml({ path: "src/404.html" });
|
|
3991
|
+
* ```
|
|
3992
|
+
*/
|
|
3993
|
+
async function resolveHtml(notFound) {
|
|
3994
|
+
if (typeof notFound === "object" && notFound.path) try {
|
|
3995
|
+
return await readFile(notFound.path, "utf8");
|
|
3996
|
+
} catch (error) {
|
|
3997
|
+
throw new Error(`build:not-found — could not read notFound.path "${notFound.path}"`, { cause: error });
|
|
3998
|
+
}
|
|
3999
|
+
return wrap(typeof notFound === "object" && notFound.body ? notFound.body : DEFAULT_BODY);
|
|
4000
|
+
}
|
|
4001
|
+
/**
|
|
3982
4002
|
* Emits `outDir/404.html`. When `config.notFound` is `true`, writes the built-in
|
|
3983
|
-
* default page;
|
|
3984
|
-
*
|
|
3985
|
-
*
|
|
4003
|
+
* default page; `{ body }` writes the supplied HTML body content inside the
|
|
4004
|
+
* minimal document shell; `{ path }` writes the referenced HTML page file
|
|
4005
|
+
* verbatim (the app owns the whole document). No-op (returns `null`) when
|
|
4006
|
+
* `notFound` is false/unset.
|
|
3986
4007
|
*
|
|
3987
4008
|
* @param ctx - Plugin context (provides `config`, `log`).
|
|
3988
4009
|
* @returns The written file path, or `null` when disabled.
|
|
@@ -3997,10 +4018,10 @@ async function generateNotFound(ctx) {
|
|
|
3997
4018
|
ctx.log.debug("build:not-found", { skipped: true });
|
|
3998
4019
|
return null;
|
|
3999
4020
|
}
|
|
4000
|
-
const
|
|
4021
|
+
const html = await resolveHtml(notFound);
|
|
4001
4022
|
await mkdir(outDir, { recursive: true });
|
|
4002
4023
|
const file = path.join(outDir, "404.html");
|
|
4003
|
-
await writeFile(file,
|
|
4024
|
+
await writeFile(file, html, "utf8");
|
|
4004
4025
|
ctx.log.debug("build:not-found", { path: file });
|
|
4005
4026
|
return { path: file };
|
|
4006
4027
|
}
|
|
@@ -4377,9 +4398,10 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
4377
4398
|
fonts,
|
|
4378
4399
|
...renderHook
|
|
4379
4400
|
});
|
|
4401
|
+
const siteCardRender = typeof config.defaultCard === "function" ? config.defaultCard : defaultSiteCard;
|
|
4380
4402
|
const renderSitePng = options.renderPng ?? makeDefaultRenderer({
|
|
4381
4403
|
fonts,
|
|
4382
|
-
render:
|
|
4404
|
+
render: siteCardRender
|
|
4383
4405
|
});
|
|
4384
4406
|
const siteName = resolveSiteName(ctx);
|
|
4385
4407
|
const defaultLocale = ctx.require(i18nPlugin).defaultLocale();
|
|
@@ -4405,7 +4427,7 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
4405
4427
|
outDir
|
|
4406
4428
|
}, tally);
|
|
4407
4429
|
})));
|
|
4408
|
-
const defaultCard = config.defaultCard === true;
|
|
4430
|
+
const defaultCard = config.defaultCard === true || typeof config.defaultCard === "function";
|
|
4409
4431
|
if (defaultCard) {
|
|
4410
4432
|
const png = await renderSitePng({
|
|
4411
4433
|
title: siteName,
|
package/package.json
CHANGED