mnfst-render 0.3.1 → 0.3.3

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.
@@ -895,25 +895,37 @@ function stripPrerenderedXDataDirectives(html) {
895
895
 
896
896
  // --- Don't bake Alpine-only state into the snapshot; only $x-driven content should be prerendered.
897
897
  // For any :attr or x-bind:attr whose expression does NOT contain $x, remove the literal attr from the tag
898
- // so Alpine re-evaluates on load. Bindings that use $x are left as-is (content stays for SEO).
898
+ // so Alpine re-evaluates on load. Bindings that use $x are left as-is (content stays for SEO), except
899
+ // :style / x-bind:style with $x: those must be removed when a baked inline style exists, or Alpine will
900
+ // overwrite prerendered values (e.g. mask-image) on hydrate when $x is briefly empty in production.
899
901
  // Use (?<!:) so we only strip literal attr=, not :attr= (e.g. class= not :class=).
900
902
  // Never touch <script> tags (loader + injected plugins must be preserved; static HTML still runs them).
901
903
  function stripPrerenderDynamicBindings(html) {
902
904
  return html.replace(/<(\w+)([^>]*)>/g, (match, tagName, attrsStr) => {
903
905
  if (tagName.toLowerCase() === 'script') return match;
904
906
  const isAnchor = tagName.toLowerCase() === 'a';
907
+ let workAttrs = attrsStr;
908
+ workAttrs = workAttrs.replace(/\s+:style=(?:"([^"]*)"|'([^']*)')/gi, (sub, d, s) => {
909
+ const val = (d !== undefined ? d : s) || '';
910
+ return val.indexOf('$x') !== -1 ? '' : sub;
911
+ });
912
+ workAttrs = workAttrs.replace(/\s+x-bind:style=(?:"([^"]*)"|'([^']*)')/gi, (sub, d, s) => {
913
+ const val = (d !== undefined ? d : s) || '';
914
+ return val.indexOf('$x') !== -1 ? '' : sub;
915
+ });
916
+
905
917
  const toStrip = new Set();
906
918
  const bindingRegex = /(?:^|\s)(?::|x-bind:)(\w+)=(?:"([^"]*)"|'([^']*)')/g;
907
919
  let m;
908
- while ((m = bindingRegex.exec(attrsStr)) !== null) {
920
+ while ((m = bindingRegex.exec(workAttrs)) !== null) {
909
921
  const attrName = (m[1] || '').toLowerCase();
910
922
  // Keep href on anchors so prerendered static navigation stays valid.
911
923
  if (attrName === 'class' || attrName === 'style' || (isAnchor && attrName === 'href')) continue;
912
924
  const val = (m[2] !== undefined ? m[2] : m[3]) || '';
913
925
  if (val.indexOf('$x') === -1) toStrip.add(attrName);
914
926
  }
915
- if (toStrip.size === 0) return match;
916
- let newAttrs = attrsStr;
927
+ if (toStrip.size === 0 && workAttrs === attrsStr) return match;
928
+ let newAttrs = workAttrs;
917
929
  for (const attr of toStrip) {
918
930
  const esc = attr.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
919
931
  newAttrs = newAttrs.replace(new RegExp(`\\s*(?<!:)${esc}="[^"]*"`, 'gi'), '');
@@ -1785,7 +1797,8 @@ async function runPrerender(config) {
1785
1797
  // keep x-text/x-bind referencing card/item — Alpine then mutates or errors on the static HTML.)
1786
1798
  await page.evaluate(() => {
1787
1799
  const loopVarRegex = /^\s*(?:\(\s*([A-Za-z_$][\w$]*)(?:\s*,\s*([A-Za-z_$][\w$]*))?\s*\)|([A-Za-z_$][\w$]*))\s+in\s+/;
1788
- const bindingAttrRegex = /^(?:x-bind:|:|x-text|x-html|x-show|x-if|x-model|x-effect|x-on:|@)/;
1800
+ // Include x-init: expanded clones still had x-init="getDescription(article)" etc.; Alpine then throws (article undefined).
1801
+ const bindingAttrRegex = /^(?:x-bind:|:|x-text|x-html|x-show|x-if|x-model|x-effect|x-init|x-on:|@)/;
1789
1802
  const hasVar = (expr, varName) => varName && new RegExp(`\\b${varName}\\b`).test(expr || '');
1790
1803
  const stripLoopBindings = (el, itemVar, indexVar) => {
1791
1804
  const nodes = [el, ...Array.from(el.querySelectorAll('*'))];
@@ -1879,7 +1892,7 @@ async function runPrerender(config) {
1879
1892
  // outside their template scope. These throw Alpine errors in live static hosting.
1880
1893
  await page.evaluate(() => {
1881
1894
  const loopVarRegex = /^\s*(?:\(\s*([A-Za-z_$][\w$]*)(?:\s*,\s*([A-Za-z_$][\w$]*))?\s*\)|([A-Za-z_$][\w$]*))\s+in\s+/;
1882
- const bindingAttrRegex = /^(?:x-bind:|:|x-text|x-html|x-show|x-if|x-model|x-effect|x-on:|@)/;
1895
+ const bindingAttrRegex = /^(?:x-bind:|:|x-text|x-html|x-show|x-if|x-model|x-effect|x-init|x-on:|@)/;
1883
1896
  const hasVar = (expr, varName) => varName && new RegExp(`\\b${varName}\\b`).test(expr || '');
1884
1897
  const elementReferencesLoopScope = (el, itemVar, indexVar) => {
1885
1898
  if (!el) return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst-render",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Render Manifest sites to static HTML for SEO",
5
5
  "type": "module",
6
6
  "bin": {