mnfst-render 0.5.36 → 0.5.37
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 +71 -15
- package/package.json +1 -1
package/manifest.render.mjs
CHANGED
|
@@ -1814,20 +1814,9 @@ function computeGlobalAssetSignature(rootDir) {
|
|
|
1814
1814
|
async function waitForVisualSettle(page, { settleMs = 300, mdWaitMs = 5000, capMs = 8000 } = {}) {
|
|
1815
1815
|
try {
|
|
1816
1816
|
await page.evaluate(async ({ settleMs, mdWaitMs, capMs }) => {
|
|
1817
|
-
//
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
while (!window.__manifestReady && Date.now() - start < capMs + 8000) {
|
|
1821
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
1822
|
-
}
|
|
1823
|
-
if (document.fonts?.ready) { try { await document.fonts.ready; } catch { /* best-effort */ } }
|
|
1824
|
-
await new Promise((r) => {
|
|
1825
|
-
const t = setTimeout(r, 250);
|
|
1826
|
-
requestAnimationFrame(() => requestAnimationFrame(() => { clearTimeout(t); r(); }));
|
|
1827
|
-
});
|
|
1828
|
-
return;
|
|
1829
|
-
}
|
|
1830
|
-
// Fallback heuristic for older framework builds:
|
|
1817
|
+
// The framework's boot signal (loader ≥0.5.190) gates the start, but it
|
|
1818
|
+
// fires once per page — per-ROUTE work is tracked by the live markdown
|
|
1819
|
+
// pending counter and the DOM heuristic below, so all three AND together.
|
|
1831
1820
|
const state = () => {
|
|
1832
1821
|
let styleLen = 0;
|
|
1833
1822
|
for (const s of document.querySelectorAll('style')) styleLen += (s.textContent || '').length;
|
|
@@ -1838,14 +1827,58 @@ async function waitForVisualSettle(page, { settleMs = 300, mdWaitMs = 5000, capM
|
|
|
1838
1827
|
const sig = `${mdEmpty}:${document.body?.innerText.length || 0}:${styleLen}:${document.fonts ? document.fonts.status : ''}`;
|
|
1839
1828
|
return { sig, mdEmpty };
|
|
1840
1829
|
};
|
|
1830
|
+
// Alpine 3.x can strand already-flushed effects when a sibling effect
|
|
1831
|
+
// creates state mid-flush — a route's x-if chain then never stamps until
|
|
1832
|
+
// something re-queues it. Bumping the data store's version re-runs every
|
|
1833
|
+
// store-reading effect: a no-op on settled pages, an unstick on stuck ones.
|
|
1834
|
+
const nudge = () => {
|
|
1835
|
+
try {
|
|
1836
|
+
if (window.Alpine?.store) {
|
|
1837
|
+
const s = window.Alpine.store('data');
|
|
1838
|
+
if (s) window.Alpine.store('data', { ...s, _dataVersion: (s._dataVersion || 0) + 1 });
|
|
1839
|
+
}
|
|
1840
|
+
} catch { /* best-effort */ }
|
|
1841
|
+
};
|
|
1842
|
+
// Responsive/variant utilities (md:row, dark:bg-*) are compiled at
|
|
1843
|
+
// runtime and the compiler throttles recompiles — a late-discovered
|
|
1844
|
+
// variant class leaves the layout in its mobile/stacked state at capture.
|
|
1845
|
+
// Hold while any variant class used in the DOM has no matching CSS rule.
|
|
1846
|
+
const unresolvedVariants = () => {
|
|
1847
|
+
try {
|
|
1848
|
+
const used = new Set();
|
|
1849
|
+
for (const el of document.querySelectorAll('[class*=":"]')) {
|
|
1850
|
+
for (const c of el.classList) if (c.includes(':') && !c.startsWith('[')) used.add(c);
|
|
1851
|
+
if (used.size > 300) break;
|
|
1852
|
+
}
|
|
1853
|
+
if (!used.size) return 0;
|
|
1854
|
+
let selectors = '';
|
|
1855
|
+
for (const sheet of document.styleSheets) {
|
|
1856
|
+
try { for (const r of sheet.cssRules) if (r.selectorText) selectors += r.selectorText + '\n'; } catch { /* cross-origin */ }
|
|
1857
|
+
}
|
|
1858
|
+
let missing = 0;
|
|
1859
|
+
for (const c of used) {
|
|
1860
|
+
if (!selectors.includes('.' + CSS.escape(c))) missing++;
|
|
1861
|
+
}
|
|
1862
|
+
return missing;
|
|
1863
|
+
} catch { return 0; }
|
|
1864
|
+
};
|
|
1841
1865
|
const start = Date.now();
|
|
1842
1866
|
let last = state();
|
|
1843
1867
|
let stableSince = Date.now();
|
|
1868
|
+
let nudged = 0;
|
|
1844
1869
|
while (Date.now() - start < capMs) {
|
|
1845
1870
|
await new Promise((r) => setTimeout(r, 100));
|
|
1871
|
+
const elapsed = Date.now() - start;
|
|
1872
|
+
if ((nudged === 0 && elapsed > 300) || (nudged === 1 && elapsed > 2000)) { nudged++; nudge(); }
|
|
1846
1873
|
const cur = state();
|
|
1874
|
+
const bootPending = !!window.__manifestReadyCoordinator && !window.__manifestReady;
|
|
1875
|
+
const inflight = (window.__manifestMarkdownPending || 0) > 0;
|
|
1847
1876
|
const mdPending = cur.mdEmpty > 0 && Date.now() - start < mdWaitMs;
|
|
1848
|
-
|
|
1877
|
+
const utilPending = elapsed < mdWaitMs + 4000 && unresolvedVariants() > 0;
|
|
1878
|
+
// A throttled compiler can DROP the request that would resolve them —
|
|
1879
|
+
// a class mutation re-triggers its observer's schedule.
|
|
1880
|
+
if (utilPending && elapsed % 500 < 100) document.body.classList.toggle('mnfst-og-nudge');
|
|
1881
|
+
if (cur.sig !== last.sig || bootPending || inflight || mdPending || utilPending) {
|
|
1849
1882
|
last = cur;
|
|
1850
1883
|
stableSince = Date.now();
|
|
1851
1884
|
} else if (Date.now() - stableSince >= settleMs) {
|
|
@@ -1953,6 +1986,11 @@ async function takeOgSnapshot(page, outputDir, pathSeg, globalAssetSignature, ca
|
|
|
1953
1986
|
// body min-h-screen + flex grow) can otherwise screenshot as blank if
|
|
1954
1987
|
// the compositor doesn't repaint between setViewport and screenshot.
|
|
1955
1988
|
await page.evaluate(() => window.scrollTo(0, 0));
|
|
1989
|
+
// Throwaway shot first: it forces the compositor to produce a fresh frame,
|
|
1990
|
+
// so the real capture below reflects the current DOM rather than a stale
|
|
1991
|
+
// surface (headless pages can sit frames behind after heavy updates).
|
|
1992
|
+
await page.screenshot({ type: 'png', clip: { x: 0, y: 0, width: 8, height: 8 }, captureBeyondViewport: false }).catch(() => { });
|
|
1993
|
+
await new Promise((r) => setTimeout(r, 120));
|
|
1956
1994
|
await page.screenshot({
|
|
1957
1995
|
path: filePath,
|
|
1958
1996
|
type: 'png',
|
|
@@ -3322,6 +3360,24 @@ async function runPrerender(config) {
|
|
|
3322
3360
|
const apply = () => {
|
|
3323
3361
|
try {
|
|
3324
3362
|
if (locale && typeof locale === 'string') document.documentElement.lang = locale;
|
|
3363
|
+
// View transitions freeze a snapshot layer over the updated DOM in
|
|
3364
|
+
// headless — OG screenshots then capture stale pre-route pixels.
|
|
3365
|
+
// Router opt-out for SPA swaps, plus a late <style> so the reset's
|
|
3366
|
+
// cross-document @view-transition{navigation:auto} is overridden
|
|
3367
|
+
// (appended after stylesheets; last descriptor wins).
|
|
3368
|
+
document.documentElement.setAttribute('data-no-view-transitions', '');
|
|
3369
|
+
const killCrossDocVT = () => {
|
|
3370
|
+
try {
|
|
3371
|
+
const s = document.createElement('style');
|
|
3372
|
+
s.textContent = '@view-transition { navigation: none }';
|
|
3373
|
+
(document.head || document.documentElement).appendChild(s);
|
|
3374
|
+
} catch { /* no-op */ }
|
|
3375
|
+
};
|
|
3376
|
+
if (document.readyState === 'loading') {
|
|
3377
|
+
document.addEventListener('DOMContentLoaded', killCrossDocVT, { once: true });
|
|
3378
|
+
} else {
|
|
3379
|
+
killCrossDocVT();
|
|
3380
|
+
}
|
|
3325
3381
|
} catch {
|
|
3326
3382
|
/* no-op */
|
|
3327
3383
|
}
|