mnfst-render 0.5.10 → 0.5.11
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 +75 -1
- package/package.json +1 -1
package/manifest.render.mjs
CHANGED
|
@@ -1271,6 +1271,49 @@ function buildSubstitutionPairs(defaultLocaleData, targetLocaleData) {
|
|
|
1271
1271
|
return pairs;
|
|
1272
1272
|
}
|
|
1273
1273
|
|
|
1274
|
+
/**
|
|
1275
|
+
/**
|
|
1276
|
+
* Prefix internal navigation links with the target locale so that prerendered
|
|
1277
|
+
* MPA pages link directly to the correct locale variant (e.g. /platform →
|
|
1278
|
+
* /fr/platform on the French page). Without this, users must rely on runtime
|
|
1279
|
+
* JS interception (`installMpaStickyLocaleLinks`) which may not be ready by
|
|
1280
|
+
* the time they click — causing navigation to fall back to English.
|
|
1281
|
+
*
|
|
1282
|
+
* Only rewrites `<a href="...">` where the href is a root-relative path that
|
|
1283
|
+
* doesn't already carry a locale prefix and isn't an excluded route.
|
|
1284
|
+
*/
|
|
1285
|
+
function prefixLocaleInternalLinks(html, locale, locales, localeRouteExclude) {
|
|
1286
|
+
if (!locale || !locales || !locales.length) return html;
|
|
1287
|
+
const localeSet = new Set(locales);
|
|
1288
|
+
const excludeSet = new Set(localeRouteExclude || []);
|
|
1289
|
+
|
|
1290
|
+
// Match <a ... href="..." ...> — capture the href value
|
|
1291
|
+
return html.replace(
|
|
1292
|
+
/(<a\b[^>]*\shref=["'])(\/?[^"'#][^"']*)(["'][^>]*>)/gi,
|
|
1293
|
+
(full, prefix, href, suffix) => {
|
|
1294
|
+
// Only process root-relative paths
|
|
1295
|
+
if (!href.startsWith('/')) return full;
|
|
1296
|
+
// Skip external protocols embedded as relative (shouldn't happen but guard)
|
|
1297
|
+
if (/^\/\//.test(href)) return full;
|
|
1298
|
+
|
|
1299
|
+
const withoutSlash = href.replace(/^\//, '');
|
|
1300
|
+
const firstSeg = withoutSlash.split('/')[0].split('#')[0].split('?')[0];
|
|
1301
|
+
|
|
1302
|
+
// Already has a locale prefix
|
|
1303
|
+
if (localeSet.has(firstSeg)) return full;
|
|
1304
|
+
|
|
1305
|
+
// Skip asset-like paths
|
|
1306
|
+
if (/\.(css|js|json|svg|png|jpg|jpeg|gif|ico|woff2?|ttf|eot|pdf|xml|txt)$/i.test(href)) return full;
|
|
1307
|
+
|
|
1308
|
+
// Respect localeRouteExclude — these routes stay locale-neutral
|
|
1309
|
+
if (excludeSet.has(firstSeg)) return full;
|
|
1310
|
+
|
|
1311
|
+
// Prefix with locale
|
|
1312
|
+
return `${prefix}/${locale}${href}${suffix}`;
|
|
1313
|
+
}
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1274
1317
|
/**
|
|
1275
1318
|
* Apply locale text substitution to rendered HTML.
|
|
1276
1319
|
* Replaces content in text nodes (between > and <) and in key attributes:
|
|
@@ -1334,6 +1377,12 @@ function generateLocaleVariantHtml({
|
|
|
1334
1377
|
// Apply locale text substitution
|
|
1335
1378
|
html = applyLocaleSubstitution(html, substitutionPairs);
|
|
1336
1379
|
|
|
1380
|
+
// Prefix internal <a> links with the locale so MPA navigation stays in-locale
|
|
1381
|
+
// without relying on runtime JS interception.
|
|
1382
|
+
if (targetLocale && targetLocale !== defaultLocale) {
|
|
1383
|
+
html = prefixLocaleInternalLinks(html, targetLocale, locales, config.localeRouteExclude);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1337
1386
|
// Standard Node.js post-processing (same sequence as processPath)
|
|
1338
1387
|
html = stripDevOnlyContent(html);
|
|
1339
1388
|
html = stripInjectedPluginScripts(html);
|
|
@@ -1778,7 +1827,13 @@ async function runPrerender(config) {
|
|
|
1778
1827
|
console.error(' npm i -D puppeteer-core @sparticuz/chromium');
|
|
1779
1828
|
process.exit(1);
|
|
1780
1829
|
}
|
|
1781
|
-
return await puppeteer.default.launch({
|
|
1830
|
+
return await puppeteer.default.launch({
|
|
1831
|
+
headless: true,
|
|
1832
|
+
args: [
|
|
1833
|
+
'--no-sandbox',
|
|
1834
|
+
'--disable-setuid-sandbox',
|
|
1835
|
+
],
|
|
1836
|
+
});
|
|
1782
1837
|
}
|
|
1783
1838
|
}
|
|
1784
1839
|
let browser = await launchBrowser();
|
|
@@ -2398,6 +2453,18 @@ async function runPrerender(config) {
|
|
|
2398
2453
|
const src = source[name];
|
|
2399
2454
|
const cur = name in currentAttrs ? currentAttrs[name] : null;
|
|
2400
2455
|
if (src !== cur) {
|
|
2456
|
+
// If the source value is null (attribute didn't exist originally)
|
|
2457
|
+
// but a reactive Alpine binding controls this attribute, skip the
|
|
2458
|
+
// restoration. Alpine will re-evaluate the binding on init and
|
|
2459
|
+
// set the correct value; nulling it in the contract would flash
|
|
2460
|
+
// the element unstyled until Alpine + async data loads catch up.
|
|
2461
|
+
// The baked value IS the correct initial render.
|
|
2462
|
+
if (src === null) {
|
|
2463
|
+
const hasBinding =
|
|
2464
|
+
(name === 'style' && (':style' in source || 'x-bind:style' in source)) ||
|
|
2465
|
+
(name === 'class' && (':class' in source || 'x-bind:class' in source));
|
|
2466
|
+
if (hasBinding) continue;
|
|
2467
|
+
}
|
|
2401
2468
|
attrsOut[name] = src; // may be null (means "remove this attribute")
|
|
2402
2469
|
dirty = true;
|
|
2403
2470
|
}
|
|
@@ -2798,6 +2865,13 @@ async function runPrerender(config) {
|
|
|
2798
2865
|
html = stripEmptyInlineMaskStyles(html);
|
|
2799
2866
|
html = stripResolvedXIconDirectives(html);
|
|
2800
2867
|
html = markPrerenderedManifestComponents(html);
|
|
2868
|
+
|
|
2869
|
+
// Prefix internal <a> links with the locale for non-default locales so
|
|
2870
|
+
// MPA navigation stays in-locale without relying on runtime JS.
|
|
2871
|
+
if (currentLocale && currentLocale !== defaultLocale) {
|
|
2872
|
+
html = prefixLocaleInternalLinks(html, currentLocale, locales, config.localeRouteExclude);
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2801
2875
|
html = rewriteHtmlAssetPaths(html, fileSegments.length);
|
|
2802
2876
|
const liveBase = config.liveUrl.replace(/\/$/, '');
|
|
2803
2877
|
const canonicalHreflang = buildCanonicalAndHreflang(is404 ? '' : pathSeg, locales, defaultLocale, liveBase);
|