mnfst-render 0.5.37 → 0.5.38
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/manifest.render.mjs +57 -6
- package/package.json +1 -1
package/manifest.render.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/* Manifest Render */
|
|
4
4
|
|
|
5
|
-
import { readFileSync, readSync, mkdirSync, writeFileSync, existsSync, rmSync, statSync, readdirSync, cpSync, unlinkSync, renameSync } from 'node:fs';
|
|
5
|
+
import { readFileSync, readSync, mkdirSync, writeFileSync, appendFileSync, existsSync, rmSync, statSync, readdirSync, cpSync, unlinkSync, renameSync } from 'node:fs';
|
|
6
6
|
import { spawnSync } from 'node:child_process';
|
|
7
7
|
import { join, resolve, dirname, relative, basename, sep } from 'node:path';
|
|
8
8
|
import { createServer } from 'node:http';
|
|
@@ -282,6 +282,10 @@ function resolveConfig() {
|
|
|
282
282
|
: [],
|
|
283
283
|
dryRun: !!cli.dryRun,
|
|
284
284
|
debugPrerender: !!cli.debugPrerender,
|
|
285
|
+
// render.icons: "lazy" strips prerender-inlined x-icon SVGs from the
|
|
286
|
+
// output — the icons plugin re-renders them at boot (decorative content;
|
|
287
|
+
// an icon-heavy nav duplicates kilobytes of identical SVG per link).
|
|
288
|
+
lazyIcons: pre.icons === 'lazy',
|
|
285
289
|
// Cap on the manifest:render-ready wait. When the data plugin dispatches
|
|
286
290
|
// the event, we resolve immediately; when it doesn't (most projects), we
|
|
287
291
|
// fall back to the timeout. 10s gives slow data plugin pipelines a
|
|
@@ -1127,6 +1131,18 @@ function stripRedundantImgSrcBindings(html) {
|
|
|
1127
1131
|
*/
|
|
1128
1132
|
// Prerender inlined Iconify SVG under <i x-icon="iterator.icon">; clear x-icon value so Alpine does not evaluate
|
|
1129
1133
|
// loop/item expressions while the attribute remains for CSS (e.g. inline layout that keys off [x-icon]).
|
|
1134
|
+
// render.icons: "lazy" — drop prerender-inlined icon SVGs from the output.
|
|
1135
|
+
// Each svg carries its resolved name (data-icon), which is written back into
|
|
1136
|
+
// the host's x-icon attribute as a static, scope-free value — so the icons
|
|
1137
|
+
// plugin re-renders it at boot even on baked clones whose expression attrs
|
|
1138
|
+
// were emptied. Only svg-as-first-child hosts match; anything else stays inline.
|
|
1139
|
+
function stripLazyIconSvgs(html) {
|
|
1140
|
+
return html.replace(
|
|
1141
|
+
/(x-icon\s*=\s*")[^"]*("[^>]*>\s*)<svg\b[^>]*\bdata-icon="([^"]+)"[^>]*>[\s\S]*?<\/svg>/gi,
|
|
1142
|
+
(m, pre, post, name) => `${pre}${name}${post}`
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1130
1146
|
function stripResolvedXIconDirectives(html) {
|
|
1131
1147
|
return html.replace(/<i\b([^>]*)>([\s\S]*?)<\/i>/gi, (full, attrs, inner) => {
|
|
1132
1148
|
if (isHydrateMarkedAttrs(attrs)) return full;
|
|
@@ -1593,6 +1609,7 @@ function generateLocaleVariantHtml({
|
|
|
1593
1609
|
html = stripRedundantImgSrcBindings(html);
|
|
1594
1610
|
html = stripEmptyInlineMaskStyles(html);
|
|
1595
1611
|
html = stripResolvedXIconDirectives(html);
|
|
1612
|
+
if (config.lazyIcons) html = stripLazyIconSvgs(html);
|
|
1596
1613
|
// markPrerenderedManifestComponents must run BEFORE stripPrerenderHydrateMarkers so it can
|
|
1597
1614
|
// detect data-hydrate markers and skip components inside hydrate islands.
|
|
1598
1615
|
html = markPrerenderedManifestComponents(html);
|
|
@@ -1874,7 +1891,8 @@ async function waitForVisualSettle(page, { settleMs = 300, mdWaitMs = 5000, capM
|
|
|
1874
1891
|
const bootPending = !!window.__manifestReadyCoordinator && !window.__manifestReady;
|
|
1875
1892
|
const inflight = (window.__manifestMarkdownPending || 0) > 0;
|
|
1876
1893
|
const mdPending = cur.mdEmpty > 0 && Date.now() - start < mdWaitMs;
|
|
1877
|
-
const utilPending =
|
|
1894
|
+
const utilPending = (window.__manifestUtilitiesPending || 0) > 0
|
|
1895
|
+
|| (elapsed < mdWaitMs + 4000 && unresolvedVariants() > 0);
|
|
1878
1896
|
// A throttled compiler can DROP the request that would resolve them —
|
|
1879
1897
|
// a class mutation re-triggers its observer's schedule.
|
|
1880
1898
|
if (utilPending && elapsed % 500 < 100) document.body.classList.toggle('mnfst-og-nudge');
|
|
@@ -1991,13 +2009,26 @@ async function takeOgSnapshot(page, outputDir, pathSeg, globalAssetSignature, ca
|
|
|
1991
2009
|
// surface (headless pages can sit frames behind after heavy updates).
|
|
1992
2010
|
await page.screenshot({ type: 'png', clip: { x: 0, y: 0, width: 8, height: 8 }, captureBeyondViewport: false }).catch(() => { });
|
|
1993
2011
|
await new Promise((r) => setTimeout(r, 120));
|
|
1994
|
-
|
|
2012
|
+
const shoot = () => page.screenshot({
|
|
1995
2013
|
path: filePath,
|
|
1996
2014
|
type: 'png',
|
|
1997
2015
|
clip: { x: 0, y: 0, width: 1200, height: 630 },
|
|
1998
2016
|
omitBackground: false,
|
|
1999
2017
|
captureBeyondViewport: false,
|
|
2000
2018
|
});
|
|
2019
|
+
await shoot();
|
|
2020
|
+
// Residual-race retry: a text-heavy page yielding a shell-weight card
|
|
2021
|
+
// means the main content missed the frame — settle again and reshoot.
|
|
2022
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
2023
|
+
let size = 0;
|
|
2024
|
+
try { size = statSync(filePath).size; } catch { break; }
|
|
2025
|
+
if (size >= 34 * 1024) break;
|
|
2026
|
+
const textLen = await page.evaluate(() => document.body?.innerText.length || 0).catch(() => 0);
|
|
2027
|
+
if (textLen < 2500) break;
|
|
2028
|
+
await new Promise((r) => setTimeout(r, 1200));
|
|
2029
|
+
await waitForVisualSettle(page, { settleMs: 400, capMs: 5000 });
|
|
2030
|
+
await shoot();
|
|
2031
|
+
}
|
|
2001
2032
|
// Sanity check: a blank 1200×630 PNG (header only, white body) is ~8–10KB;
|
|
2002
2033
|
// a content-rich page is 50KB+. When the resulting file is suspiciously
|
|
2003
2034
|
// small the snapshot is treated as failed and the renderer falls through
|
|
@@ -4447,6 +4478,16 @@ async function runPrerender(config) {
|
|
|
4447
4478
|
});
|
|
4448
4479
|
});
|
|
4449
4480
|
|
|
4481
|
+
// (render.icons: "lazy" is applied on the serialized HTML string — see
|
|
4482
|
+
// stripLazyIconSvgs. Doing it in the live DOM re-triggers the icons
|
|
4483
|
+
// plugin's observer, which re-injects every svg before serialization.)
|
|
4484
|
+
|
|
4485
|
+
// x-virtual recomputes spacer geometry at boot; measured heights vary
|
|
4486
|
+
// run to run — zero them so identical content serializes identically.
|
|
4487
|
+
await page.evaluate(() => {
|
|
4488
|
+
document.querySelectorAll('[data-virtual-spacer]').forEach((el) => { el.style.height = '0px'; });
|
|
4489
|
+
});
|
|
4490
|
+
|
|
4450
4491
|
// Deterministic output: randomized CSS anchor-positioning names
|
|
4451
4492
|
// (--dropdown-x7f2, --popover-…, --anchor-…) are regenerated per run and
|
|
4452
4493
|
// made every render a phantom diff. Renumber them sequentially in DOM
|
|
@@ -4547,6 +4588,7 @@ async function runPrerender(config) {
|
|
|
4547
4588
|
html = stripRedundantImgSrcBindings(html);
|
|
4548
4589
|
html = stripEmptyInlineMaskStyles(html);
|
|
4549
4590
|
html = stripResolvedXIconDirectives(html);
|
|
4591
|
+
if (config.lazyIcons) html = stripLazyIconSvgs(html);
|
|
4550
4592
|
html = markPrerenderedManifestComponents(html);
|
|
4551
4593
|
|
|
4552
4594
|
// Prefix internal <a> links with the locale for non-default locales so
|
|
@@ -4790,9 +4832,18 @@ async function runPrerender(config) {
|
|
|
4790
4832
|
if (bundleUtilities) {
|
|
4791
4833
|
const utilMerged = mergeUtilityCssBlocks(utilityBlocks);
|
|
4792
4834
|
if (utilMerged.trim()) {
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4835
|
+
// Append to prerender.tailwind.css when it exists — one render-blocking
|
|
4836
|
+
// stylesheet instead of two, same cascade order (utilities last). The
|
|
4837
|
+
// separate file remains only for projects without a Tailwind build.
|
|
4838
|
+
const twPath = join(outputResolved, 'prerender.tailwind.css');
|
|
4839
|
+
if (existsSync(twPath)) {
|
|
4840
|
+
appendFileSync(twPath, `\n/* Manifest custom utilities */\n${utilMerged}\n`, 'utf8');
|
|
4841
|
+
process.stdout.write('prerender: merged custom utilities into prerender.tailwind.css\n');
|
|
4842
|
+
} else {
|
|
4843
|
+
writeFileSync(join(outputResolved, 'prerender.utilities.css'), `${utilMerged}\n`, 'utf8');
|
|
4844
|
+
process.stdout.write('prerender: wrote prerender.utilities.css (Manifest custom utilities)\n');
|
|
4845
|
+
postProcessInjectStylesheetLink(outputResolved, 'prerender.utilities.css', routerBasePath || '');
|
|
4846
|
+
}
|
|
4796
4847
|
}
|
|
4797
4848
|
}
|
|
4798
4849
|
|