mnfst-render 0.5.14 → 0.5.15
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 +44 -7
- package/package.json +1 -1
package/manifest.render.mjs
CHANGED
|
@@ -619,14 +619,20 @@ function stripDevOnlyContent(html) {
|
|
|
619
619
|
// leaving it in place would cause Alpine to execute synchronously during HTML
|
|
620
620
|
// parse, before plugins have a chance to register their directives.
|
|
621
621
|
function stripInjectedPluginScripts(html) {
|
|
622
|
+
// Safety-net regex strip for any Manifest plugin scripts that survived the
|
|
623
|
+
// DOM-level removal in the Puppeteer evaluate phase. Uses a broad pattern
|
|
624
|
+
// that matches ANY `manifest.*.js` or `manifest.*.min.js` script — no need
|
|
625
|
+
// to enumerate individual plugin names. New plugins are covered automatically.
|
|
622
626
|
const pluginPattern =
|
|
623
|
-
/<script[^>]*\ssrc=["'][^"']*manifest\.
|
|
627
|
+
/<script[^>]*\ssrc=["'][^"']*manifest\.[a-z][\w.-]*\.(?:min\.)?js["'][^>]*>\s*<\/script>/gi;
|
|
624
628
|
let out = html.replace(pluginPattern, '');
|
|
629
|
+
// Alpine (re-injected by the loader at runtime after plugin registration)
|
|
625
630
|
const alpinePattern =
|
|
626
631
|
/<script[^>]*\ssrc=["'][^"']*\/alpinejs@[^"']*["'][^>]*>\s*<\/script>/gi;
|
|
627
632
|
out = out.replace(alpinePattern, '');
|
|
633
|
+
// Runtime library scripts loaded by plugins (yaml parser, markdown, etc.)
|
|
628
634
|
const runtimePattern =
|
|
629
|
-
/<script[^>]*\ssrc=["'][^"']*(?:papaparse
|
|
635
|
+
/<script[^>]*\ssrc=["'][^"']*(?:papaparse[^"']*\.min\.js|marked[^"']*\.min\.js|highlight[^"']*\.min\.js|js-yaml[^"']*\.min\.js)[^"']*["'][^>]*>\s*<\/script>/gi;
|
|
630
636
|
out = out.replace(runtimePattern, '');
|
|
631
637
|
return out;
|
|
632
638
|
}
|
|
@@ -1993,6 +1999,22 @@ async function runPrerender(config) {
|
|
|
1993
1999
|
// (`hydratePrerenderedPage` in manifest.js) reads the contract and
|
|
1994
2000
|
// restores source attributes before Alpine starts.
|
|
1995
2001
|
await page.evaluateOnNewDocument(() => {
|
|
2002
|
+
// Snapshot the script srcs that exist in the author's original HTML
|
|
2003
|
+
// BEFORE any loader/plugin injects additional scripts. Used later to
|
|
2004
|
+
// strip runtime-injected scripts from the serialized output while
|
|
2005
|
+
// keeping author-intentional ones (analytics, third-party widgets, etc.).
|
|
2006
|
+
window.__manifestOriginalScriptSrcs = new Set();
|
|
2007
|
+
const _snapScripts = () => {
|
|
2008
|
+
document.querySelectorAll('script[src]').forEach(s => {
|
|
2009
|
+
window.__manifestOriginalScriptSrcs.add(s.getAttribute('src'));
|
|
2010
|
+
});
|
|
2011
|
+
};
|
|
2012
|
+
if (document.readyState === 'loading') {
|
|
2013
|
+
document.addEventListener('DOMContentLoaded', _snapScripts, { once: true });
|
|
2014
|
+
}
|
|
2015
|
+
// Also snap immediately for any scripts already parsed
|
|
2016
|
+
_snapScripts();
|
|
2017
|
+
|
|
1996
2018
|
// element -> { attrName: originalValue (null if attribute was absent) }
|
|
1997
2019
|
// Keyed by reference so detached elements drop out naturally.
|
|
1998
2020
|
const sourceAttrs = new Map();
|
|
@@ -2722,13 +2744,14 @@ async function runPrerender(config) {
|
|
|
2722
2744
|
runBatch(() => {
|
|
2723
2745
|
document.querySelectorAll('template[x-for][data-prerender-static-generated="1"]').forEach((tpl) => {
|
|
2724
2746
|
if (tpl.hasAttribute('data-hydrate') || tpl.closest('[data-hydrate]')) return;
|
|
2725
|
-
//
|
|
2726
|
-
//
|
|
2727
|
-
//
|
|
2728
|
-
//
|
|
2747
|
+
// $x-driven x-for: keep the template so Alpine can re-render the
|
|
2748
|
+
// list at runtime (locale switching, filtering, etc.), but remove
|
|
2749
|
+
// the static clones — Alpine creates fresh clones on init and does
|
|
2750
|
+
// NOT adopt existing DOM nodes, so leaving them produces duplicates.
|
|
2751
|
+
// Individual article/pricing pages still have full baked content
|
|
2752
|
+
// (via x-text/x-html); the x-for list is only the index/grid view.
|
|
2729
2753
|
const xFor = (tpl.getAttribute('x-for') || '');
|
|
2730
2754
|
if (xFor.includes('$x')) {
|
|
2731
|
-
// Remove static clones (siblings with same tag+class as template's first child)
|
|
2732
2755
|
const first = tpl.content?.firstElementChild;
|
|
2733
2756
|
if (first) {
|
|
2734
2757
|
const tag = first.tagName;
|
|
@@ -2834,6 +2857,20 @@ async function runPrerender(config) {
|
|
|
2834
2857
|
toRemove.forEach((el) => { if (document.contains(el)) el.remove(); });
|
|
2835
2858
|
});
|
|
2836
2859
|
|
|
2860
|
+
// Remove scripts that were injected at runtime (by the loader, plugins,
|
|
2861
|
+
// or third-party libraries) but were NOT in the author's original HTML.
|
|
2862
|
+
// This is done in the browser context (before serialization) so the
|
|
2863
|
+
// removal is permanent in the captured outerHTML. The approach is
|
|
2864
|
+
// future-proof: new plugins and arbitrary third-party scripts are handled
|
|
2865
|
+
// automatically without updating a hardcoded allowlist.
|
|
2866
|
+
await page.evaluate(() => {
|
|
2867
|
+
const originals = window.__manifestOriginalScriptSrcs || new Set();
|
|
2868
|
+
document.querySelectorAll('script[src]').forEach(s => {
|
|
2869
|
+
const src = s.getAttribute('src');
|
|
2870
|
+
if (src && !originals.has(src)) s.remove();
|
|
2871
|
+
});
|
|
2872
|
+
});
|
|
2873
|
+
|
|
2837
2874
|
let html = await page.evaluate(() => document.documentElement.outerHTML);
|
|
2838
2875
|
// Inject the hydration contract blob into the raw HTML *before* caching
|
|
2839
2876
|
// it for locale variant generation, so every locale variant inherits the
|