mnfst-render 0.5.7 → 0.5.10

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.
@@ -1,2 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import '../manifest.render.mjs';
2
+ import { main } from '../manifest.render.mjs';
3
+
4
+ main().catch((err) => {
5
+ console.error('prerender:', err);
6
+ process.exit(1);
7
+ });
@@ -248,9 +248,9 @@ function resolveConfig() {
248
248
  debugPrerender: !!cli.debugPrerender,
249
249
  // Cap on the manifest:render-ready wait. When the data plugin dispatches
250
250
  // the event, we resolve immediately; when it doesn't (most projects), we
251
- // fall back to the timeout. Lowered from 25000 the earlier settle
252
- // waits already give plugins enough time to finish.
253
- pipelineTimeout: 6000,
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,
254
254
  };
255
255
  }
256
256
 
@@ -980,8 +980,13 @@ function markPrerenderedManifestComponents(html) {
980
980
  // the runtime restoration reinstate the <x-*> tag and the components
981
981
  // plugin processes it normally on load.
982
982
  if (/\bdata-hydrate\b/i.test(a)) return full;
983
- const spacer = /\S/.test(a) ? ' ' : '';
984
- return `<${tag}${a}${spacer}data-pre-rendered="1">`;
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">`;
985
990
  });
986
991
  }
987
992
 
@@ -2028,21 +2033,27 @@ async function runPrerender(config) {
2028
2033
  timeout: Math.min(timeout, 30000),
2029
2034
  });
2030
2035
 
2031
- // Belt-and-suspenders settle waits. Each one is bounded short because
2032
- // the authoritative `manifest:render-ready` wait below is what we really
2033
- // rely on. These earlier waits exist as fallbacks for projects whose
2034
- // data plugins don't dispatch the modern signal but they shouldn't
2035
- // dominate per-path runtime when they DO time out.
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.
2036
2047
  await Promise.race([
2037
2048
  page.evaluate(() => {
2038
2049
  return new Promise((resolve) => {
2039
2050
  const done = () => resolve();
2040
- const t = setTimeout(done, 1500); // was 6000
2051
+ const t = setTimeout(done, 3000);
2041
2052
  window.addEventListener(
2042
2053
  'manifest:routing-ready',
2043
2054
  () => {
2044
2055
  clearTimeout(t);
2045
- setTimeout(done, 500); // was 2000
2056
+ setTimeout(done, 1000);
2046
2057
  },
2047
2058
  { once: true }
2048
2059
  );
@@ -2052,12 +2063,13 @@ async function runPrerender(config) {
2052
2063
  ]).catch(() => { });
2053
2064
 
2054
2065
  // Ensure the dynamic loader has injected at least one plugin script.
2055
- // In practice this happens within ~100ms; the 1500ms cap is generous.
2066
+ // In practice this happens within ~100ms but allow up to 3s for cold
2067
+ // CDN cache or slow disk.
2056
2068
  await page.evaluate(() => {
2057
2069
  return new Promise((resolve) => {
2058
2070
  const check = () => document.querySelectorAll('script[src*="manifest"]').length >= 2;
2059
2071
  if (check()) return resolve();
2060
- const deadline = Date.now() + 1500; // was 5000
2072
+ const deadline = Date.now() + 3000;
2061
2073
  const t = setInterval(() => {
2062
2074
  if (check() || Date.now() >= deadline) {
2063
2075
  clearInterval(t);
@@ -2067,21 +2079,21 @@ async function runPrerender(config) {
2067
2079
  });
2068
2080
  }).catch(() => { });
2069
2081
 
2070
- // Network idle: shorter idle window + shorter cap. Most plugin scripts
2071
- // and data fetches complete in under 2s on a healthy local server.
2072
- await page.waitForNetworkIdle({ idleTime: 800, timeout: 4000 }).catch(() => { });
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(() => { });
2073
2086
 
2074
- // DOM stability: 300ms quiet window is plenty after networkIdle has
2075
- // already drained pending fetches.
2087
+ // DOM stability after network idle.
2076
2088
  await page.evaluate(() => {
2077
2089
  return new Promise((resolve) => {
2078
2090
  const observer = new MutationObserver(() => {
2079
2091
  clearTimeout(stable);
2080
- stable = setTimeout(finish, 300); // was 800
2092
+ stable = setTimeout(finish, 500);
2081
2093
  });
2082
2094
  observer.observe(document.documentElement, { childList: true, subtree: true, characterData: true });
2083
2095
  const finish = () => { observer.disconnect(); resolve(); };
2084
- let stable = setTimeout(finish, 300); // was 800
2096
+ let stable = setTimeout(finish, 500);
2085
2097
  });
2086
2098
  }).catch(() => { });
2087
2099
 
@@ -3030,7 +3042,24 @@ async function runPrerender(config) {
3030
3042
 
3031
3043
  }
3032
3044
 
3033
- main().catch((err) => {
3034
- console.error('prerender:', err);
3035
- process.exit(1);
3036
- });
3045
+ // Auto-run main() when this file is the direct entry point (node manifest.render.mjs)
3046
+ // but NOT when imported by the bin wrapper or test harness. The bin wrapper
3047
+ // calls main() explicitly; test harnesses only need the exported helpers.
3048
+ const _isDirectEntry = (() => {
3049
+ try {
3050
+ const arg1 = process.argv[1];
3051
+ if (!arg1) return false;
3052
+ const invoked = String(new URL('file://' + resolve(arg1)));
3053
+ return invoked === import.meta.url;
3054
+ } catch { return false; }
3055
+ })();
3056
+
3057
+ if (_isDirectEntry) {
3058
+ main().catch((err) => {
3059
+ console.error('prerender:', err);
3060
+ process.exit(1);
3061
+ });
3062
+ }
3063
+
3064
+ // Exports for the CLI bin script and for unit testing.
3065
+ export { main, markPrerenderedManifestComponents };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst-render",
3
- "version": "0.5.7",
3
+ "version": "0.5.10",
4
4
  "description": "Render Manifest sites to static HTML for SEO",
5
5
  "type": "module",
6
6
  "bin": {