mnfst-render 0.5.6 → 0.5.9
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 +64 -23
- package/package.json +1 -1
package/manifest.render.mjs
CHANGED
|
@@ -150,11 +150,11 @@ async function waitForManifestRenderReady(page, { allLocales, currentLocale, tim
|
|
|
150
150
|
)
|
|
151
151
|
.catch((e) => ({ ok: false, reason: 'evaluate', message: String(e) }));
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
// Note: render-ready wait timeouts are silently tolerated. Earlier versions
|
|
154
|
+
// logged a warning per path, but it fires on essentially every route in
|
|
155
|
+
// projects whose data plugins don't dispatch `manifest:render-ready` (i.e.
|
|
156
|
+
// most of them), drowning the terminal in noise. The fallback timeout is
|
|
157
|
+
// intentional and benign — the DOM is still captured.
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
// --- Config ------------------------------------------------------------------
|
|
@@ -246,7 +246,11 @@ function resolveConfig() {
|
|
|
246
246
|
: [],
|
|
247
247
|
dryRun: !!cli.dryRun,
|
|
248
248
|
debugPrerender: !!cli.debugPrerender,
|
|
249
|
-
|
|
249
|
+
// Cap on the manifest:render-ready wait. When the data plugin dispatches
|
|
250
|
+
// the event, we resolve immediately; when it doesn't (most projects), we
|
|
251
|
+
// fall back to the timeout. 10s gives slow data plugin pipelines a
|
|
252
|
+
// chance while bounding worst-case per-path overhead.
|
|
253
|
+
pipelineTimeout: 10000,
|
|
250
254
|
};
|
|
251
255
|
}
|
|
252
256
|
|
|
@@ -976,8 +980,13 @@ function markPrerenderedManifestComponents(html) {
|
|
|
976
980
|
// the runtime restoration reinstate the <x-*> tag and the components
|
|
977
981
|
// plugin processes it normally on load.
|
|
978
982
|
if (/\bdata-hydrate\b/i.test(a)) return full;
|
|
979
|
-
|
|
980
|
-
|
|
983
|
+
// CRITICAL: always insert a leading space before the injected attribute.
|
|
984
|
+
// For tags with no existing attributes (e.g. `<x-sidebar>`), `a` is empty
|
|
985
|
+
// and concatenating directly produces `<x-sidebardata-pre-rendered=...>`,
|
|
986
|
+
// which mangles the tag name and prevents the components plugin from
|
|
987
|
+
// recognising it. The trailing-space normalisation on `a` keeps the
|
|
988
|
+
// output tidy when there ARE existing attributes.
|
|
989
|
+
return `<${tag}${a.replace(/\s+$/, '')} data-pre-rendered="1">`;
|
|
981
990
|
});
|
|
982
991
|
}
|
|
983
992
|
|
|
@@ -2024,16 +2033,27 @@ async function runPrerender(config) {
|
|
|
2024
2033
|
timeout: Math.min(timeout, 30000),
|
|
2025
2034
|
});
|
|
2026
2035
|
|
|
2036
|
+
// Settle waits. These give Manifest plugins (especially the components
|
|
2037
|
+
// plugin, which lazy-fetches each component HTML over the network) time
|
|
2038
|
+
// to finish loading and expanding everything before we snapshot. Each
|
|
2039
|
+
// wait is bounded; large projects with many components need the full
|
|
2040
|
+
// budget on cold runs, but small projects settle long before the cap.
|
|
2041
|
+
//
|
|
2042
|
+
// Lowered from the original "any wait could hold the prerender for ~50s
|
|
2043
|
+
// per path" defaults, but kept generous enough that Playcom-scale sites
|
|
2044
|
+
// (~10 preloaded components, dozens of lazy components) actually finish
|
|
2045
|
+
// expanding before snapshot. Earlier reductions were too aggressive and
|
|
2046
|
+
// left unexpanded `<x-*>` placeholders in the output.
|
|
2027
2047
|
await Promise.race([
|
|
2028
2048
|
page.evaluate(() => {
|
|
2029
2049
|
return new Promise((resolve) => {
|
|
2030
2050
|
const done = () => resolve();
|
|
2031
|
-
const t = setTimeout(done,
|
|
2051
|
+
const t = setTimeout(done, 3000);
|
|
2032
2052
|
window.addEventListener(
|
|
2033
2053
|
'manifest:routing-ready',
|
|
2034
2054
|
() => {
|
|
2035
2055
|
clearTimeout(t);
|
|
2036
|
-
setTimeout(done,
|
|
2056
|
+
setTimeout(done, 1000);
|
|
2037
2057
|
},
|
|
2038
2058
|
{ once: true }
|
|
2039
2059
|
);
|
|
@@ -2042,13 +2062,14 @@ async function runPrerender(config) {
|
|
|
2042
2062
|
new Promise((_, rej) => setTimeout(() => rej(new Error('ready timeout')), timeout)),
|
|
2043
2063
|
]).catch(() => { });
|
|
2044
2064
|
|
|
2045
|
-
// Ensure
|
|
2046
|
-
//
|
|
2065
|
+
// Ensure the dynamic loader has injected at least one plugin script.
|
|
2066
|
+
// In practice this happens within ~100ms but allow up to 3s for cold
|
|
2067
|
+
// CDN cache or slow disk.
|
|
2047
2068
|
await page.evaluate(() => {
|
|
2048
2069
|
return new Promise((resolve) => {
|
|
2049
2070
|
const check = () => document.querySelectorAll('script[src*="manifest"]').length >= 2;
|
|
2050
2071
|
if (check()) return resolve();
|
|
2051
|
-
const deadline = Date.now() +
|
|
2072
|
+
const deadline = Date.now() + 3000;
|
|
2052
2073
|
const t = setInterval(() => {
|
|
2053
2074
|
if (check() || Date.now() >= deadline) {
|
|
2054
2075
|
clearInterval(t);
|
|
@@ -2058,19 +2079,21 @@ async function runPrerender(config) {
|
|
|
2058
2079
|
});
|
|
2059
2080
|
}).catch(() => { });
|
|
2060
2081
|
|
|
2061
|
-
|
|
2082
|
+
// Network idle: drain pending fetches (component templates, data sources,
|
|
2083
|
+
// markdown files, icon SVGs). Larger projects need the full window;
|
|
2084
|
+
// small ones settle in well under 1 second.
|
|
2085
|
+
await page.waitForNetworkIdle({ idleTime: 1000, timeout: 8000 }).catch(() => { });
|
|
2062
2086
|
|
|
2087
|
+
// DOM stability after network idle.
|
|
2063
2088
|
await page.evaluate(() => {
|
|
2064
2089
|
return new Promise((resolve) => {
|
|
2065
2090
|
const observer = new MutationObserver(() => {
|
|
2066
2091
|
clearTimeout(stable);
|
|
2067
|
-
stable = setTimeout(
|
|
2092
|
+
stable = setTimeout(finish, 500);
|
|
2068
2093
|
});
|
|
2069
2094
|
observer.observe(document.documentElement, { childList: true, subtree: true, characterData: true });
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
resolve();
|
|
2073
|
-
}, 800);
|
|
2095
|
+
const finish = () => { observer.disconnect(); resolve(); };
|
|
2096
|
+
let stable = setTimeout(finish, 500);
|
|
2074
2097
|
});
|
|
2075
2098
|
}).catch(() => { });
|
|
2076
2099
|
|
|
@@ -3019,7 +3042,25 @@ async function runPrerender(config) {
|
|
|
3019
3042
|
|
|
3020
3043
|
}
|
|
3021
3044
|
|
|
3022
|
-
main()
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3045
|
+
// Only run main() when invoked as the CLI entry point — this lets tests
|
|
3046
|
+
// import this module to access internal helpers (e.g.
|
|
3047
|
+
// markPrerenderedManifestComponents) without triggering a full prerender.
|
|
3048
|
+
const isCliEntry = (() => {
|
|
3049
|
+
try {
|
|
3050
|
+
const invoked = process.argv[1] && new URL('file://' + process.argv[1]).href;
|
|
3051
|
+
return invoked === import.meta.url;
|
|
3052
|
+
} catch {
|
|
3053
|
+
return false;
|
|
3054
|
+
}
|
|
3055
|
+
})();
|
|
3056
|
+
|
|
3057
|
+
if (isCliEntry) {
|
|
3058
|
+
main().catch((err) => {
|
|
3059
|
+
console.error('prerender:', err);
|
|
3060
|
+
process.exit(1);
|
|
3061
|
+
});
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
// Exports for unit testing. These are intentionally not part of any public
|
|
3065
|
+
// API — they exist so the e2e harness can directly exercise pure helpers.
|
|
3066
|
+
export { markPrerenderedManifestComponents };
|