mnfst-render 0.1.7 → 0.1.9
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 +78 -11
- package/package.json +1 -1
package/manifest.render.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/* Manifest Render */
|
|
4
4
|
|
|
5
|
-
import { readFileSync, mkdirSync, writeFileSync, existsSync, rmSync, statSync, readdirSync, cpSync, unlinkSync } from 'node:fs';
|
|
5
|
+
import { readFileSync, readSync, mkdirSync, writeFileSync, existsSync, rmSync, statSync, readdirSync, cpSync, unlinkSync } from 'node:fs';
|
|
6
6
|
import { spawnSync } from 'node:child_process';
|
|
7
7
|
import { join, resolve, dirname, relative, basename, sep } from 'node:path';
|
|
8
8
|
import { createServer } from 'node:http';
|
|
@@ -313,31 +313,55 @@ function discoverDataPaths(manifest, rootDir, wildcardBases = [], locales = [])
|
|
|
313
313
|
return wildcardBases.some((base) => rest.startsWith(base + '/'));
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
function
|
|
316
|
+
function expandCandidates(rawPath, sourceKey) {
|
|
317
|
+
const p = String(rawPath || '').replace(/^\/+|\/+$/g, '');
|
|
318
|
+
if (!p) return [];
|
|
319
|
+
const candidates = [p];
|
|
320
|
+
if (wildcardBases.length === 0) return candidates;
|
|
321
|
+
if (!sourceKey || !wildcardBases.includes(sourceKey)) return candidates;
|
|
322
|
+
const parts = p.split('/');
|
|
323
|
+
const hasLocalePrefix = parts.length > 1 && localeSet.has(parts[0].toLowerCase());
|
|
324
|
+
if (hasLocalePrefix) {
|
|
325
|
+
const locale = parts[0];
|
|
326
|
+
const rest = parts.slice(1).join('/');
|
|
327
|
+
if (rest && !rest.startsWith(sourceKey + '/')) candidates.push(`${locale}/${sourceKey}/${rest}`);
|
|
328
|
+
} else if (!p.startsWith(sourceKey + '/')) {
|
|
329
|
+
candidates.push(`${sourceKey}/${p}`);
|
|
330
|
+
}
|
|
331
|
+
return candidates;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function addFilePaths(value, sourceKey) {
|
|
317
335
|
if (typeof value !== 'string' || !value.startsWith('/')) return;
|
|
318
336
|
const filePath = join(rootDir, value.slice(1));
|
|
319
337
|
if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) {
|
|
320
338
|
parseYamlPaths(filePath).forEach((p) => {
|
|
321
|
-
|
|
339
|
+
for (const c of expandCandidates(p, sourceKey)) {
|
|
340
|
+
if (shouldIncludeDataPath(c)) paths.add('/' + c);
|
|
341
|
+
}
|
|
322
342
|
});
|
|
323
343
|
} else if (filePath.endsWith('.json')) {
|
|
324
344
|
parseJsonPaths(filePath).forEach((p) => {
|
|
325
345
|
const normalized = p.startsWith('/') ? p.slice(1) : p;
|
|
326
|
-
|
|
346
|
+
for (const c of expandCandidates(normalized, sourceKey)) {
|
|
347
|
+
if (shouldIncludeDataPath(c)) paths.add('/' + c);
|
|
348
|
+
}
|
|
327
349
|
});
|
|
328
350
|
} else if (filePath.endsWith('.csv')) {
|
|
329
351
|
parseCsvPaths(filePath).forEach((p) => {
|
|
330
352
|
const normalized = p.startsWith('/') ? p.slice(1) : p;
|
|
331
|
-
|
|
353
|
+
for (const c of expandCandidates(normalized, sourceKey)) {
|
|
354
|
+
if (shouldIncludeDataPath(c)) paths.add('/' + c);
|
|
355
|
+
}
|
|
332
356
|
});
|
|
333
357
|
}
|
|
334
358
|
}
|
|
335
359
|
|
|
336
|
-
for (const value of Object.
|
|
337
|
-
if (typeof value === 'string') addFilePaths(value);
|
|
360
|
+
for (const [sourceKey, value] of Object.entries(data)) {
|
|
361
|
+
if (typeof value === 'string') addFilePaths(value, sourceKey);
|
|
338
362
|
else if (value && typeof value === 'object') {
|
|
339
363
|
for (const v of Object.values(value)) {
|
|
340
|
-
if (typeof v === 'string') addFilePaths(v);
|
|
364
|
+
if (typeof v === 'string') addFilePaths(v, sourceKey);
|
|
341
365
|
}
|
|
342
366
|
}
|
|
343
367
|
}
|
|
@@ -472,6 +496,38 @@ function indexHtmlUsesTailwind(rootDir) {
|
|
|
472
496
|
return /\sdata-tailwind(?:=(["']).*?\1)?/i.test(html) && /<script[^>]*manifest\.min\.js/i.test(html);
|
|
473
497
|
}
|
|
474
498
|
|
|
499
|
+
function promptContinueWithRuntimeTailwind(rootDir) {
|
|
500
|
+
const installMsg = [
|
|
501
|
+
'prerender: tailwindcss package is not installed for this project.',
|
|
502
|
+
'',
|
|
503
|
+
'To enable static Tailwind CSS compilation, install:',
|
|
504
|
+
' npm i -D tailwindcss @tailwindcss/cli',
|
|
505
|
+
'',
|
|
506
|
+
`Project: ${rootDir}`,
|
|
507
|
+
'',
|
|
508
|
+
'Continue prerender with runtime data-tailwind instead? [P]roceed/[E]nd (default: P): ',
|
|
509
|
+
].join('\n');
|
|
510
|
+
process.stdout.write(`${installMsg}\n`);
|
|
511
|
+
|
|
512
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
513
|
+
process.stdout.write(
|
|
514
|
+
'prerender: non-interactive terminal detected; continuing with runtime data-tailwind behavior.\n'
|
|
515
|
+
);
|
|
516
|
+
return true;
|
|
517
|
+
}
|
|
518
|
+
const buf = Buffer.alloc(1);
|
|
519
|
+
let answer = '';
|
|
520
|
+
while (true) {
|
|
521
|
+
const n = readSync(0, buf, 0, 1, null);
|
|
522
|
+
if (n <= 0) break;
|
|
523
|
+
const ch = buf.toString('utf8', 0, n);
|
|
524
|
+
if (ch === '\n' || ch === '\r') break;
|
|
525
|
+
answer += ch;
|
|
526
|
+
}
|
|
527
|
+
const normalized = answer.trim().toLowerCase();
|
|
528
|
+
return normalized === '' || normalized === 'p' || normalized === 'proceed' || normalized === 'y' || normalized === 'yes';
|
|
529
|
+
}
|
|
530
|
+
|
|
475
531
|
/**
|
|
476
532
|
* Build a static Tailwind stylesheet via @tailwindcss/cli (v4+), scanning project sources.
|
|
477
533
|
* Only runs when the project opts in (data-tailwind on manifest script) or manifest.prerender.tailwind === true.
|
|
@@ -483,6 +539,16 @@ function runTailwindCliForPrerender(rootDir, outputDir, pre) {
|
|
|
483
539
|
if (!usesTailwind) return false;
|
|
484
540
|
|
|
485
541
|
const outCss = join(outputDir, 'prerender.tailwind.css');
|
|
542
|
+
try {
|
|
543
|
+
require.resolve('tailwindcss', { paths: [rootDir] });
|
|
544
|
+
} catch {
|
|
545
|
+
const proceed = promptContinueWithRuntimeTailwind(rootDir);
|
|
546
|
+
if (!proceed) {
|
|
547
|
+
throw new Error('prerender aborted: install tailwindcss/@tailwindcss/cli or disable prerender.tailwind.');
|
|
548
|
+
}
|
|
549
|
+
process.stdout.write('prerender: continuing with runtime data-tailwind behavior.\n');
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
486
552
|
let inputPath = null;
|
|
487
553
|
let createdTempInput = false;
|
|
488
554
|
const userInput = pre?.tailwindInput;
|
|
@@ -498,9 +564,8 @@ function runTailwindCliForPrerender(rootDir, outputDir, pre) {
|
|
|
498
564
|
const outputBasename = basename(outputDir);
|
|
499
565
|
const defaultContent = [
|
|
500
566
|
'**/*.html',
|
|
501
|
-
'**/*.{js,mjs,css}',
|
|
502
|
-
'**/*.json',
|
|
503
567
|
'!**/node_modules/**',
|
|
568
|
+
'!**/dist/**',
|
|
504
569
|
`!**/${outputBasename}/**`,
|
|
505
570
|
];
|
|
506
571
|
const contentGlobs = Array.isArray(pre?.tailwindContent) && pre.tailwindContent.length > 0
|
|
@@ -1354,7 +1419,9 @@ async function runPrerender(config) {
|
|
|
1354
1419
|
let html = await page.evaluate(() => document.documentElement.outerHTML);
|
|
1355
1420
|
html = stripDevOnlyContent(html);
|
|
1356
1421
|
html = stripInjectedPluginScripts(html);
|
|
1357
|
-
|
|
1422
|
+
if (tailwindBuilt) {
|
|
1423
|
+
html = stripRuntimeTailwindArtifacts(html);
|
|
1424
|
+
}
|
|
1358
1425
|
if (bundleUtilities) {
|
|
1359
1426
|
const extracted = extractUtilityStyleBlocks(html);
|
|
1360
1427
|
html = extracted.html;
|