mnfst-render 0.3.0 → 0.3.1

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.
@@ -1664,6 +1664,8 @@ async function runPrerender(config) {
1664
1664
  return {
1665
1665
  templateCount: templates.length,
1666
1666
  nonCollapsedTemplateCount: templates.filter((t) => t.getAttribute('data-prerender-collapsed') !== '1').length,
1667
+ hint:
1668
+ 'entries.staticGenerated is read before the x-for mark pass and is always false; use stage post-xfor-mark for data-prerender-static-generated.',
1667
1669
  entries,
1668
1670
  listDiagnostics,
1669
1671
  };
@@ -1758,6 +1760,26 @@ async function runPrerender(config) {
1758
1760
  });
1759
1761
  });
1760
1762
 
1763
+ if (config.debugPrerender) {
1764
+ const afterMark = await page.evaluate(() => {
1765
+ const rows = [];
1766
+ for (const tpl of document.querySelectorAll('template[x-for]')) {
1767
+ rows.push({
1768
+ xFor: (tpl.getAttribute('x-for') || '').slice(0, 140),
1769
+ collapsed: tpl.getAttribute('data-prerender-collapsed') === '1',
1770
+ staticGenerated: tpl.getAttribute('data-prerender-static-generated') === '1',
1771
+ });
1772
+ }
1773
+ return {
1774
+ templateCount: rows.length,
1775
+ staticMarkedCount: rows.filter((r) => r.staticGenerated).length,
1776
+ collapsedCount: rows.filter((r) => r.collapsed).length,
1777
+ entries: rows.slice(0, 60),
1778
+ };
1779
+ }).catch(() => null);
1780
+ pushDebug({ path: displayPath, stage: 'post-xfor-mark', metrics: afterMark });
1781
+ }
1782
+
1761
1783
  // Strip loop-scope bindings from x-for clones while <template> nodes still exist.
1762
1784
  // (If we remove static templates first, querySelectorAll('template[x-for]') misses them and clones
1763
1785
  // keep x-text/x-bind referencing card/item — Alpine then mutates or errors on the static HTML.)
@@ -1821,10 +1843,35 @@ async function runPrerender(config) {
1821
1843
  });
1822
1844
 
1823
1845
  // Remove static x-for templates once static clones are generated.
1824
- // This prevents Alpine from rendering duplicate lists at runtime.
1846
+ // Alpine registers a cleanup on <template x-for> that removes every node in _x_lookup when the
1847
+ // template is detached — so tpl.remove() alone deletes all sibling clones (empty grids in output).
1848
+ // Replace each clone with a deep cloneNode first so teardown targets detached nodes; copies stay in DOM.
1825
1849
  await page.evaluate(() => {
1826
- document.querySelectorAll('template[x-for][data-prerender-static-generated="1"]').forEach((tpl) => {
1827
- tpl.remove();
1850
+ const A = window.Alpine;
1851
+ const runBatch = typeof A?.mutateDom === 'function' ? (fn) => A.mutateDom(fn) : (fn) => fn();
1852
+ runBatch(() => {
1853
+ document.querySelectorAll('template[x-for][data-prerender-static-generated="1"]').forEach((tpl) => {
1854
+ const parent = tpl.parentNode;
1855
+ if (!parent) {
1856
+ tpl.remove();
1857
+ return;
1858
+ }
1859
+ const first = tpl.content?.firstElementChild;
1860
+ if (!first) {
1861
+ tpl.remove();
1862
+ return;
1863
+ }
1864
+ const tag = first.tagName;
1865
+ const cls = first.getAttribute('class') || '';
1866
+ let n = tpl.nextElementSibling;
1867
+ while (n && n.tagName === tag) {
1868
+ if ((n.getAttribute('class') || '') !== cls) break;
1869
+ const next = n.nextElementSibling;
1870
+ n.replaceWith(n.cloneNode(true));
1871
+ n = next;
1872
+ }
1873
+ tpl.remove();
1874
+ });
1828
1875
  });
1829
1876
  });
1830
1877
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst-render",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Render Manifest sites to static HTML for SEO",
5
5
  "type": "module",
6
6
  "bin": {