prev-cli 0.24.11 → 0.24.13
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/dist/cli.js +495 -150
- package/dist/preview-runtime/build-optimized.d.ts +11 -0
- package/dist/preview-runtime/tailwind.d.ts +11 -0
- package/dist/preview-runtime/vendors.d.ts +6 -0
- package/dist/vite/config-parser.d.ts +13 -0
- package/dist/vite/preview-types.d.ts +70 -0
- package/dist/vite/previews.d.ts +6 -0
- package/package.json +3 -2
- package/src/preview-runtime/build-optimized.test.ts +47 -0
- package/src/preview-runtime/build-optimized.ts +136 -0
- package/src/preview-runtime/tailwind.test.ts +30 -0
- package/src/preview-runtime/tailwind.ts +64 -0
- package/src/preview-runtime/vendors.test.ts +15 -0
- package/src/preview-runtime/vendors.ts +52 -0
- package/src/theme/previews/AtlasPreview.tsx +528 -0
- package/src/theme/previews/ComponentPreview.tsx +180 -0
- package/src/theme/previews/FlowPreview.tsx +270 -0
- package/src/theme/previews/PreviewRouter.tsx +189 -0
- package/src/theme/previews/ScreenPreview.tsx +297 -0
- package/src/theme/previews/index.ts +5 -0
package/dist/cli.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { parseArgs } from "util";
|
|
5
5
|
import path11 from "path";
|
|
6
|
-
import { existsSync as
|
|
7
|
-
import { fileURLToPath as
|
|
6
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync6, rmSync as rmSync4, readFileSync as readFileSync7 } from "fs";
|
|
7
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8
8
|
|
|
9
9
|
// src/vite/start.ts
|
|
10
|
-
import { createServer as createServer2, build as
|
|
10
|
+
import { createServer as createServer2, build as build3, preview } from "vite";
|
|
11
11
|
|
|
12
12
|
// src/vite/config.ts
|
|
13
13
|
import { createLogger } from "vite";
|
|
@@ -17,8 +17,8 @@ import remarkGfm from "remark-gfm";
|
|
|
17
17
|
import rehypeHighlight from "rehype-highlight";
|
|
18
18
|
import path8 from "path";
|
|
19
19
|
import os from "os";
|
|
20
|
-
import { fileURLToPath as
|
|
21
|
-
import { existsSync as
|
|
20
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
21
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
22
22
|
|
|
23
23
|
// src/vite/plugins/pages-plugin.ts
|
|
24
24
|
import path2 from "path";
|
|
@@ -402,10 +402,89 @@ function entryPlugin(rootDir) {
|
|
|
402
402
|
// src/vite/previews.ts
|
|
403
403
|
import fg2 from "fast-glob";
|
|
404
404
|
import path4 from "path";
|
|
405
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
406
|
+
|
|
407
|
+
// src/vite/config-parser.ts
|
|
405
408
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
409
|
+
import * as yaml from "js-yaml";
|
|
410
|
+
|
|
411
|
+
// src/vite/preview-types.ts
|
|
412
|
+
import { z } from "zod";
|
|
413
|
+
var configSchema = z.object({
|
|
414
|
+
tags: z.union([
|
|
415
|
+
z.array(z.string()),
|
|
416
|
+
z.string().transform((s) => [s])
|
|
417
|
+
]).optional(),
|
|
418
|
+
category: z.string().optional(),
|
|
419
|
+
status: z.enum(["draft", "stable", "deprecated"]).optional(),
|
|
420
|
+
title: z.string().optional(),
|
|
421
|
+
description: z.string().optional(),
|
|
422
|
+
order: z.number().optional()
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// src/vite/config-parser.ts
|
|
426
|
+
async function parsePreviewConfig(filePath) {
|
|
427
|
+
if (!existsSync2(filePath)) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
try {
|
|
431
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
432
|
+
const parsed = yaml.load(content);
|
|
433
|
+
const result = configSchema.safeParse(parsed);
|
|
434
|
+
if (result.success) {
|
|
435
|
+
return result.data;
|
|
436
|
+
}
|
|
437
|
+
console.warn(`Invalid config at ${filePath}:`, result.error.message);
|
|
438
|
+
return null;
|
|
439
|
+
} catch (err) {
|
|
440
|
+
console.warn(`Error parsing config at ${filePath}:`, err);
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
async function parseFlowDefinition(filePath) {
|
|
445
|
+
if (!existsSync2(filePath)) {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
try {
|
|
449
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
450
|
+
const parsed = yaml.load(content);
|
|
451
|
+
if (!parsed.name || !Array.isArray(parsed.steps)) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
return parsed;
|
|
455
|
+
} catch (err) {
|
|
456
|
+
console.warn(`Error parsing flow at ${filePath}:`, err);
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
async function parseAtlasDefinition(filePath) {
|
|
461
|
+
if (!existsSync2(filePath)) {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
try {
|
|
465
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
466
|
+
const parsed = yaml.load(content);
|
|
467
|
+
if (!parsed.name || !parsed.hierarchy?.root || !parsed.hierarchy?.areas) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
return parsed;
|
|
471
|
+
} catch (err) {
|
|
472
|
+
console.warn(`Error parsing atlas at ${filePath}:`, err);
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/vite/previews.ts
|
|
478
|
+
var PREVIEW_TYPE_FOLDERS = ["components", "screens", "flows", "atlas"];
|
|
479
|
+
var TYPE_MAP = {
|
|
480
|
+
components: "component",
|
|
481
|
+
screens: "screen",
|
|
482
|
+
flows: "flow",
|
|
483
|
+
atlas: "atlas"
|
|
484
|
+
};
|
|
406
485
|
async function scanPreviews(rootDir) {
|
|
407
486
|
const previewsDir = path4.join(rootDir, "previews");
|
|
408
|
-
if (!
|
|
487
|
+
if (!existsSync3(previewsDir)) {
|
|
409
488
|
return [];
|
|
410
489
|
}
|
|
411
490
|
const entryFiles = await fg2.glob("**/{index.html,App.tsx,App.jsx,index.tsx,index.jsx}", {
|
|
@@ -434,7 +513,7 @@ async function scanPreviewFiles(previewDir) {
|
|
|
434
513
|
ignore: ["node_modules/**", "dist/**"]
|
|
435
514
|
});
|
|
436
515
|
return files.map((file) => {
|
|
437
|
-
const content =
|
|
516
|
+
const content = readFileSync3(path4.join(previewDir, file), "utf-8");
|
|
438
517
|
const ext = path4.extname(file).slice(1);
|
|
439
518
|
return {
|
|
440
519
|
path: file,
|
|
@@ -462,10 +541,168 @@ async function buildPreviewConfig(previewDir) {
|
|
|
462
541
|
tailwind: true
|
|
463
542
|
};
|
|
464
543
|
}
|
|
544
|
+
async function scanPreviewUnits(rootDir) {
|
|
545
|
+
const previewsDir = path4.join(rootDir, "previews");
|
|
546
|
+
if (!existsSync3(previewsDir)) {
|
|
547
|
+
return [];
|
|
548
|
+
}
|
|
549
|
+
const units = [];
|
|
550
|
+
for (const typeFolder of PREVIEW_TYPE_FOLDERS) {
|
|
551
|
+
const typeDir = path4.join(previewsDir, typeFolder);
|
|
552
|
+
if (!existsSync3(typeDir))
|
|
553
|
+
continue;
|
|
554
|
+
const type = TYPE_MAP[typeFolder];
|
|
555
|
+
const entries = await fg2.glob("*/", {
|
|
556
|
+
cwd: typeDir,
|
|
557
|
+
onlyDirectories: true,
|
|
558
|
+
deep: 1
|
|
559
|
+
});
|
|
560
|
+
for (const entry of entries) {
|
|
561
|
+
const name = entry.replace(/\/$/, "");
|
|
562
|
+
const unitDir = path4.join(typeDir, name);
|
|
563
|
+
const files = await detectUnitFiles(unitDir, type);
|
|
564
|
+
if (!files.index)
|
|
565
|
+
continue;
|
|
566
|
+
const configPath = existsSync3(path4.join(unitDir, "config.yaml")) ? path4.join(unitDir, "config.yaml") : path4.join(unitDir, "config.yml");
|
|
567
|
+
const config = await parsePreviewConfig(configPath);
|
|
568
|
+
units.push({
|
|
569
|
+
type,
|
|
570
|
+
name,
|
|
571
|
+
path: unitDir,
|
|
572
|
+
route: `/_preview/${typeFolder}/${name}`,
|
|
573
|
+
config,
|
|
574
|
+
files
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return units;
|
|
579
|
+
}
|
|
580
|
+
async function detectUnitFiles(unitDir, type) {
|
|
581
|
+
const allFiles = await fg2.glob("*", { cwd: unitDir });
|
|
582
|
+
let index;
|
|
583
|
+
if (type === "flow" || type === "atlas") {
|
|
584
|
+
index = allFiles.find((f) => f === "index.yaml" || f === "index.yml");
|
|
585
|
+
} else {
|
|
586
|
+
const priorities = [
|
|
587
|
+
"index.tsx",
|
|
588
|
+
"index.jsx",
|
|
589
|
+
"index.ts",
|
|
590
|
+
"index.js",
|
|
591
|
+
"App.tsx",
|
|
592
|
+
"App.jsx",
|
|
593
|
+
"index.html"
|
|
594
|
+
];
|
|
595
|
+
index = priorities.find((p) => allFiles.includes(p));
|
|
596
|
+
}
|
|
597
|
+
const result = {
|
|
598
|
+
index: index || ""
|
|
599
|
+
};
|
|
600
|
+
if (type === "screen" && index) {
|
|
601
|
+
const stateFiles = allFiles.filter((f) => (f.endsWith(".tsx") || f.endsWith(".jsx")) && f !== index).sort();
|
|
602
|
+
if (stateFiles.length > 0) {
|
|
603
|
+
result.states = stateFiles;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (type === "component") {
|
|
607
|
+
if (allFiles.includes("schema.ts")) {
|
|
608
|
+
result.schema = "schema.ts";
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (allFiles.includes("docs.mdx") || allFiles.includes("README.mdx")) {
|
|
612
|
+
result.docs = allFiles.find((f) => f.endsWith(".mdx"));
|
|
613
|
+
}
|
|
614
|
+
return result;
|
|
615
|
+
}
|
|
465
616
|
|
|
466
|
-
// src/preview-runtime/
|
|
617
|
+
// src/preview-runtime/vendors.ts
|
|
467
618
|
import { build } from "esbuild";
|
|
468
|
-
|
|
619
|
+
import { dirname } from "path";
|
|
620
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
621
|
+
var __dirname2 = dirname(fileURLToPath2(import.meta.url));
|
|
622
|
+
async function buildVendorBundle() {
|
|
623
|
+
try {
|
|
624
|
+
const entryCode = `
|
|
625
|
+
import * as React from 'react'
|
|
626
|
+
import * as ReactDOM from 'react-dom'
|
|
627
|
+
import { createRoot } from 'react-dom/client'
|
|
628
|
+
export { jsx, jsxs, Fragment } from 'react/jsx-runtime'
|
|
629
|
+
export { React, ReactDOM, createRoot }
|
|
630
|
+
export default React
|
|
631
|
+
`;
|
|
632
|
+
const result = await build({
|
|
633
|
+
stdin: {
|
|
634
|
+
contents: entryCode,
|
|
635
|
+
loader: "ts",
|
|
636
|
+
resolveDir: __dirname2
|
|
637
|
+
},
|
|
638
|
+
bundle: true,
|
|
639
|
+
write: false,
|
|
640
|
+
format: "esm",
|
|
641
|
+
target: "es2020",
|
|
642
|
+
minify: true
|
|
643
|
+
});
|
|
644
|
+
const jsFile = result.outputFiles?.find((f) => f.path.endsWith(".js")) || result.outputFiles?.[0];
|
|
645
|
+
if (!jsFile) {
|
|
646
|
+
return { success: false, code: "", error: "No output generated" };
|
|
647
|
+
}
|
|
648
|
+
return { success: true, code: jsFile.text };
|
|
649
|
+
} catch (err) {
|
|
650
|
+
return {
|
|
651
|
+
success: false,
|
|
652
|
+
code: "",
|
|
653
|
+
error: err instanceof Error ? err.message : String(err)
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// src/preview-runtime/build-optimized.ts
|
|
659
|
+
import { build as build2 } from "esbuild";
|
|
660
|
+
|
|
661
|
+
// src/preview-runtime/tailwind.ts
|
|
662
|
+
import { $ } from "bun";
|
|
663
|
+
import { mkdtempSync, mkdirSync, writeFileSync as writeFileSync2, readFileSync as readFileSync4, rmSync } from "fs";
|
|
664
|
+
import { join, dirname as dirname2 } from "path";
|
|
665
|
+
import { tmpdir } from "os";
|
|
666
|
+
async function compileTailwind(files) {
|
|
667
|
+
const tempDir = mkdtempSync(join(tmpdir(), "prev-tailwind-"));
|
|
668
|
+
try {
|
|
669
|
+
for (const file of files) {
|
|
670
|
+
const filePath = join(tempDir, file.path);
|
|
671
|
+
const parentDir = dirname2(filePath);
|
|
672
|
+
mkdirSync(parentDir, { recursive: true });
|
|
673
|
+
writeFileSync2(filePath, file.content);
|
|
674
|
+
}
|
|
675
|
+
const configContent = `
|
|
676
|
+
module.exports = {
|
|
677
|
+
content: [${JSON.stringify(tempDir + "/**/*.{tsx,jsx,ts,js,html}")}],
|
|
678
|
+
}
|
|
679
|
+
`;
|
|
680
|
+
const configPath = join(tempDir, "tailwind.config.cjs");
|
|
681
|
+
writeFileSync2(configPath, configContent);
|
|
682
|
+
const inputCss = `
|
|
683
|
+
@tailwind base;
|
|
684
|
+
@tailwind components;
|
|
685
|
+
@tailwind utilities;
|
|
686
|
+
`;
|
|
687
|
+
const inputPath = join(tempDir, "input.css");
|
|
688
|
+
writeFileSync2(inputPath, inputCss);
|
|
689
|
+
const outputPath = join(tempDir, "output.css");
|
|
690
|
+
await $`bunx tailwindcss -c ${configPath} -i ${inputPath} -o ${outputPath} --minify`.quiet();
|
|
691
|
+
const css = readFileSync4(outputPath, "utf-8");
|
|
692
|
+
return { success: true, css };
|
|
693
|
+
} catch (err) {
|
|
694
|
+
return {
|
|
695
|
+
success: false,
|
|
696
|
+
css: "",
|
|
697
|
+
error: err instanceof Error ? err.message : String(err)
|
|
698
|
+
};
|
|
699
|
+
} finally {
|
|
700
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// src/preview-runtime/build-optimized.ts
|
|
705
|
+
async function buildOptimizedPreview(config, options) {
|
|
469
706
|
try {
|
|
470
707
|
const virtualFs = {};
|
|
471
708
|
for (const file of config.files) {
|
|
@@ -475,25 +712,18 @@ async function buildPreviewHtml(config) {
|
|
|
475
712
|
}
|
|
476
713
|
const entryFile = config.files.find((f) => f.path === config.entry);
|
|
477
714
|
if (!entryFile) {
|
|
478
|
-
return { html: "", error: `Entry file not found: ${config.entry}` };
|
|
715
|
+
return { success: false, html: "", css: "", error: `Entry file not found: ${config.entry}` };
|
|
479
716
|
}
|
|
480
717
|
const hasDefaultExport = /export\s+default/.test(entryFile.content);
|
|
718
|
+
const userCssCollected = [];
|
|
481
719
|
const entryCode = hasDefaultExport ? `
|
|
482
|
-
import React from '
|
|
483
|
-
import { createRoot } from 'react-dom/client'
|
|
720
|
+
import React, { createRoot } from '${options.vendorPath}'
|
|
484
721
|
import App from './${config.entry}'
|
|
485
|
-
|
|
486
722
|
const root = createRoot(document.getElementById('root'))
|
|
487
723
|
root.render(React.createElement(App))
|
|
488
|
-
` : `
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const result = await build({
|
|
492
|
-
stdin: {
|
|
493
|
-
contents: entryCode,
|
|
494
|
-
loader: "tsx",
|
|
495
|
-
resolveDir: "/"
|
|
496
|
-
},
|
|
724
|
+
` : `import './${config.entry}'`;
|
|
725
|
+
const result = await build2({
|
|
726
|
+
stdin: { contents: entryCode, loader: "tsx", resolveDir: "/" },
|
|
497
727
|
bundle: true,
|
|
498
728
|
write: false,
|
|
499
729
|
format: "esm",
|
|
@@ -501,84 +731,78 @@ async function buildPreviewHtml(config) {
|
|
|
501
731
|
jsxImportSource: "react",
|
|
502
732
|
target: "es2020",
|
|
503
733
|
minify: true,
|
|
504
|
-
plugins: [
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
for (const ext of [".tsx", ".ts", ".jsx", ".js", ".css"]) {
|
|
523
|
-
if (virtualFs[resolved + ext]) {
|
|
524
|
-
resolved = resolved + ext;
|
|
525
|
-
break;
|
|
734
|
+
plugins: [
|
|
735
|
+
{
|
|
736
|
+
name: "optimized-preview",
|
|
737
|
+
setup(build3) {
|
|
738
|
+
build3.onResolve({ filter: new RegExp(options.vendorPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")) }, (args) => {
|
|
739
|
+
return { path: args.path, external: true };
|
|
740
|
+
});
|
|
741
|
+
build3.onResolve({ filter: /^react(-dom)?(\/.*)?$/ }, () => {
|
|
742
|
+
return { path: options.vendorPath, external: true };
|
|
743
|
+
});
|
|
744
|
+
build3.onResolve({ filter: /^\./ }, (args) => {
|
|
745
|
+
let resolved = args.path.replace(/^\.\//, "");
|
|
746
|
+
if (!resolved.includes(".")) {
|
|
747
|
+
for (const ext of [".tsx", ".ts", ".jsx", ".js", ".css"]) {
|
|
748
|
+
if (virtualFs[resolved + ext]) {
|
|
749
|
+
resolved = resolved + ext;
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
526
752
|
}
|
|
527
753
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const style = document.createElement('style');
|
|
539
|
-
style.textContent = \`${css}\`;
|
|
540
|
-
document.head.appendChild(style);
|
|
541
|
-
`,
|
|
542
|
-
loader: "js"
|
|
543
|
-
};
|
|
754
|
+
return { path: resolved, namespace: "virtual" };
|
|
755
|
+
});
|
|
756
|
+
build3.onLoad({ filter: /.*/, namespace: "virtual" }, (args) => {
|
|
757
|
+
const file = virtualFs[args.path];
|
|
758
|
+
if (file) {
|
|
759
|
+
if (file.loader === "css") {
|
|
760
|
+
userCssCollected.push(file.contents);
|
|
761
|
+
return { contents: "", loader: "js" };
|
|
762
|
+
}
|
|
763
|
+
return { contents: file.contents, loader: file.loader };
|
|
544
764
|
}
|
|
545
|
-
return { contents:
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
});
|
|
765
|
+
return { contents: "", loader: "empty" };
|
|
766
|
+
});
|
|
767
|
+
}
|
|
549
768
|
}
|
|
550
|
-
|
|
769
|
+
]
|
|
551
770
|
});
|
|
552
|
-
const jsFile = result.outputFiles
|
|
771
|
+
const jsFile = result.outputFiles?.find((f) => f.path.endsWith(".js")) || result.outputFiles?.[0];
|
|
553
772
|
const jsCode = jsFile?.text || "";
|
|
773
|
+
let css = "";
|
|
774
|
+
if (config.tailwind) {
|
|
775
|
+
const tailwindResult = await compileTailwind(config.files.map((f) => ({ path: f.path, content: f.content })));
|
|
776
|
+
if (tailwindResult.success)
|
|
777
|
+
css = tailwindResult.css;
|
|
778
|
+
}
|
|
779
|
+
const userCss = userCssCollected.join(`
|
|
780
|
+
`);
|
|
781
|
+
const allCss = css + `
|
|
782
|
+
` + userCss;
|
|
554
783
|
const html = `<!DOCTYPE html>
|
|
555
784
|
<html lang="en">
|
|
556
785
|
<head>
|
|
557
786
|
<meta charset="UTF-8">
|
|
558
787
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
559
788
|
<title>Preview</title>
|
|
560
|
-
<
|
|
561
|
-
<style>
|
|
562
|
-
body { margin: 0; }
|
|
563
|
-
#root { min-height: 100vh; }
|
|
564
|
-
</style>
|
|
789
|
+
<style>${allCss}</style>
|
|
790
|
+
<style>body { margin: 0; } #root { min-height: 100vh; }</style>
|
|
565
791
|
</head>
|
|
566
792
|
<body>
|
|
567
793
|
<div id="root"></div>
|
|
794
|
+
<script type="module" src="${options.vendorPath}"></script>
|
|
568
795
|
<script type="module">${jsCode}</script>
|
|
569
796
|
</body>
|
|
570
797
|
</html>`;
|
|
571
|
-
return { html };
|
|
798
|
+
return { success: true, html, css: allCss };
|
|
572
799
|
} catch (err) {
|
|
573
|
-
return {
|
|
574
|
-
html: "",
|
|
575
|
-
error: err instanceof Error ? err.message : String(err)
|
|
576
|
-
};
|
|
800
|
+
return { success: false, html: "", css: "", error: err instanceof Error ? err.message : String(err) };
|
|
577
801
|
}
|
|
578
802
|
}
|
|
579
803
|
|
|
580
804
|
// src/vite/plugins/previews-plugin.ts
|
|
581
|
-
import { existsSync as
|
|
805
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
582
806
|
import path5 from "path";
|
|
583
807
|
var VIRTUAL_MODULE_ID2 = "virtual:prev-previews";
|
|
584
808
|
var RESOLVED_VIRTUAL_MODULE_ID2 = "\x00" + VIRTUAL_MODULE_ID2;
|
|
@@ -596,12 +820,39 @@ function previewsPlugin(rootDir) {
|
|
|
596
820
|
},
|
|
597
821
|
async load(id) {
|
|
598
822
|
if (id === RESOLVED_VIRTUAL_MODULE_ID2) {
|
|
599
|
-
const
|
|
600
|
-
|
|
823
|
+
const units = await scanPreviewUnits(rootDir);
|
|
824
|
+
const legacyPreviews = await scanPreviews(rootDir);
|
|
825
|
+
return `
|
|
826
|
+
// Multi-type preview units
|
|
827
|
+
export const previewUnits = ${JSON.stringify(units)};
|
|
828
|
+
|
|
829
|
+
// Legacy flat previews (backwards compatibility)
|
|
830
|
+
export const previews = ${JSON.stringify(legacyPreviews)};
|
|
831
|
+
|
|
832
|
+
// Filtering helpers
|
|
833
|
+
export function getByType(type) {
|
|
834
|
+
return previewUnits.filter(u => u.type === type);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
export function getByTags(tags) {
|
|
838
|
+
return previewUnits.filter(u =>
|
|
839
|
+
u.config?.tags?.some(t => tags.includes(t))
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
export function getByCategory(category) {
|
|
844
|
+
return previewUnits.filter(u => u.config?.category === category);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
export function getByStatus(status) {
|
|
848
|
+
return previewUnits.filter(u => u.config?.status === status);
|
|
849
|
+
}
|
|
850
|
+
`;
|
|
601
851
|
}
|
|
602
852
|
},
|
|
603
853
|
handleHotUpdate({ file, server }) {
|
|
604
|
-
|
|
854
|
+
const previewsPath = path5.sep + "previews" + path5.sep;
|
|
855
|
+
if ((file.includes(previewsPath) || file.includes("/previews/")) && /\.(html|tsx|ts|jsx|js|css|yaml|yml|mdx)$/.test(file)) {
|
|
605
856
|
const mod = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_MODULE_ID2);
|
|
606
857
|
if (mod) {
|
|
607
858
|
server.moduleGraph.invalidateModule(mod);
|
|
@@ -614,31 +865,43 @@ function previewsPlugin(rootDir) {
|
|
|
614
865
|
return;
|
|
615
866
|
const distDir = path5.join(rootDir, "dist");
|
|
616
867
|
const targetDir = path5.join(distDir, "_preview");
|
|
868
|
+
const vendorsDir = path5.join(targetDir, "_vendors");
|
|
617
869
|
const previewsDir = path5.join(rootDir, "previews");
|
|
618
870
|
const oldPreviewsDir = path5.join(distDir, "previews");
|
|
619
|
-
if (
|
|
620
|
-
|
|
871
|
+
if (existsSync4(oldPreviewsDir)) {
|
|
872
|
+
rmSync2(oldPreviewsDir, { recursive: true });
|
|
621
873
|
}
|
|
622
|
-
if (
|
|
623
|
-
|
|
874
|
+
if (existsSync4(targetDir)) {
|
|
875
|
+
rmSync2(targetDir, { recursive: true });
|
|
624
876
|
}
|
|
625
877
|
const previews = await scanPreviews(rootDir);
|
|
626
878
|
if (previews.length === 0)
|
|
627
879
|
return;
|
|
628
880
|
console.log(`
|
|
629
881
|
Building ${previews.length} preview(s)...`);
|
|
882
|
+
console.log(" Building shared vendor bundle...");
|
|
883
|
+
mkdirSync2(vendorsDir, { recursive: true });
|
|
884
|
+
const vendorResult = await buildVendorBundle();
|
|
885
|
+
if (!vendorResult.success) {
|
|
886
|
+
console.error(` ✗ Vendor bundle: ${vendorResult.error}`);
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
writeFileSync3(path5.join(vendorsDir, "runtime.js"), vendorResult.code);
|
|
890
|
+
console.log(" ✓ _vendors/runtime.js");
|
|
630
891
|
for (const preview of previews) {
|
|
631
892
|
const previewDir = path5.join(previewsDir, preview.name);
|
|
632
893
|
try {
|
|
633
894
|
const config = await buildPreviewConfig(previewDir);
|
|
634
|
-
const
|
|
635
|
-
|
|
895
|
+
const depth = preview.name.split("/").length;
|
|
896
|
+
const vendorPath = "../".repeat(depth) + "_vendors/runtime.js";
|
|
897
|
+
const result = await buildOptimizedPreview(config, { vendorPath });
|
|
898
|
+
if (!result.success) {
|
|
636
899
|
console.error(` ✗ ${preview.name}: ${result.error}`);
|
|
637
900
|
continue;
|
|
638
901
|
}
|
|
639
902
|
const outputDir = path5.join(targetDir, preview.name);
|
|
640
|
-
|
|
641
|
-
|
|
903
|
+
mkdirSync2(outputDir, { recursive: true });
|
|
904
|
+
writeFileSync3(path5.join(outputDir, "index.html"), result.html);
|
|
642
905
|
console.log(` ✓ ${preview.name}`);
|
|
643
906
|
} catch (err) {
|
|
644
907
|
console.error(` ✗ ${preview.name}: ${err}`);
|
|
@@ -758,15 +1021,15 @@ function validateConfig(raw) {
|
|
|
758
1021
|
return config;
|
|
759
1022
|
}
|
|
760
1023
|
// src/config/loader.ts
|
|
761
|
-
import { readFileSync as
|
|
1024
|
+
import { readFileSync as readFileSync5, existsSync as existsSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
762
1025
|
import path6 from "path";
|
|
763
|
-
import
|
|
1026
|
+
import yaml2 from "js-yaml";
|
|
764
1027
|
function findConfigFile(rootDir) {
|
|
765
1028
|
const yamlPath = path6.join(rootDir, ".prev.yaml");
|
|
766
1029
|
const ymlPath = path6.join(rootDir, ".prev.yml");
|
|
767
|
-
if (
|
|
1030
|
+
if (existsSync5(yamlPath))
|
|
768
1031
|
return yamlPath;
|
|
769
|
-
if (
|
|
1032
|
+
if (existsSync5(ymlPath))
|
|
770
1033
|
return ymlPath;
|
|
771
1034
|
return null;
|
|
772
1035
|
}
|
|
@@ -776,8 +1039,8 @@ function loadConfig(rootDir) {
|
|
|
776
1039
|
return defaultConfig;
|
|
777
1040
|
}
|
|
778
1041
|
try {
|
|
779
|
-
const content =
|
|
780
|
-
const raw =
|
|
1042
|
+
const content = readFileSync5(configPath, "utf-8");
|
|
1043
|
+
const raw = yaml2.load(content);
|
|
781
1044
|
return validateConfig(raw);
|
|
782
1045
|
} catch (error) {
|
|
783
1046
|
console.warn(`Warning: Failed to parse ${configPath}:`, error);
|
|
@@ -786,13 +1049,13 @@ function loadConfig(rootDir) {
|
|
|
786
1049
|
}
|
|
787
1050
|
function saveConfig(rootDir, config) {
|
|
788
1051
|
const configPath = findConfigFile(rootDir) || path6.join(rootDir, ".prev.yaml");
|
|
789
|
-
const content =
|
|
1052
|
+
const content = yaml2.dump(config, {
|
|
790
1053
|
indent: 2,
|
|
791
1054
|
lineWidth: -1,
|
|
792
1055
|
quotingType: '"',
|
|
793
1056
|
forceQuotes: false
|
|
794
1057
|
});
|
|
795
|
-
|
|
1058
|
+
writeFileSync4(configPath, content, "utf-8");
|
|
796
1059
|
}
|
|
797
1060
|
function updateOrder(rootDir, pathKey, order) {
|
|
798
1061
|
const config = loadConfig(rootDir);
|
|
@@ -800,7 +1063,7 @@ function updateOrder(rootDir, pathKey, order) {
|
|
|
800
1063
|
saveConfig(rootDir, config);
|
|
801
1064
|
}
|
|
802
1065
|
// src/utils/debug.ts
|
|
803
|
-
import { mkdirSync as
|
|
1066
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
804
1067
|
import path7 from "path";
|
|
805
1068
|
|
|
806
1069
|
class DebugCollector {
|
|
@@ -880,11 +1143,11 @@ class DebugCollector {
|
|
|
880
1143
|
summary: this.generateSummary()
|
|
881
1144
|
};
|
|
882
1145
|
const debugDir = path7.join(this.rootDir, ".prev-debug");
|
|
883
|
-
|
|
1146
|
+
mkdirSync3(debugDir, { recursive: true });
|
|
884
1147
|
const date = new Date;
|
|
885
1148
|
const filename = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}-${String(date.getHours()).padStart(2, "0")}-${String(date.getMinutes()).padStart(2, "0")}-${String(date.getSeconds()).padStart(2, "0")}.json`;
|
|
886
1149
|
const filepath = path7.join(debugDir, filename);
|
|
887
|
-
|
|
1150
|
+
writeFileSync5(filepath, JSON.stringify(report, null, 2));
|
|
888
1151
|
return filepath;
|
|
889
1152
|
}
|
|
890
1153
|
}
|
|
@@ -898,6 +1161,12 @@ function getDebugCollector() {
|
|
|
898
1161
|
}
|
|
899
1162
|
|
|
900
1163
|
// src/vite/config.ts
|
|
1164
|
+
var TYPE_SINGULAR = {
|
|
1165
|
+
components: "component",
|
|
1166
|
+
screens: "screen",
|
|
1167
|
+
flows: "flow",
|
|
1168
|
+
atlas: "atlas"
|
|
1169
|
+
};
|
|
901
1170
|
function createFriendlyLogger() {
|
|
902
1171
|
const logger = createLogger("info", { allowClearScreen: false });
|
|
903
1172
|
const hiddenPatterns = [
|
|
@@ -952,12 +1221,12 @@ function createFriendlyLogger() {
|
|
|
952
1221
|
};
|
|
953
1222
|
}
|
|
954
1223
|
function findCliRoot2() {
|
|
955
|
-
let dir = path8.dirname(
|
|
1224
|
+
let dir = path8.dirname(fileURLToPath3(import.meta.url));
|
|
956
1225
|
for (let i = 0;i < 10; i++) {
|
|
957
1226
|
const pkgPath = path8.join(dir, "package.json");
|
|
958
|
-
if (
|
|
1227
|
+
if (existsSync6(pkgPath)) {
|
|
959
1228
|
try {
|
|
960
|
-
const pkg = JSON.parse(
|
|
1229
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
|
|
961
1230
|
if (pkg.name === "prev-cli") {
|
|
962
1231
|
return dir;
|
|
963
1232
|
}
|
|
@@ -968,11 +1237,11 @@ function findCliRoot2() {
|
|
|
968
1237
|
break;
|
|
969
1238
|
dir = parent;
|
|
970
1239
|
}
|
|
971
|
-
return path8.dirname(path8.dirname(
|
|
1240
|
+
return path8.dirname(path8.dirname(fileURLToPath3(import.meta.url)));
|
|
972
1241
|
}
|
|
973
1242
|
function findNodeModules(cliRoot2) {
|
|
974
1243
|
const localNodeModules = path8.join(cliRoot2, "node_modules");
|
|
975
|
-
if (
|
|
1244
|
+
if (existsSync6(path8.join(localNodeModules, "react"))) {
|
|
976
1245
|
return localNodeModules;
|
|
977
1246
|
}
|
|
978
1247
|
let dir = cliRoot2;
|
|
@@ -980,7 +1249,7 @@ function findNodeModules(cliRoot2) {
|
|
|
980
1249
|
const parent = path8.dirname(dir);
|
|
981
1250
|
if (parent === dir)
|
|
982
1251
|
break;
|
|
983
|
-
if (path8.basename(parent) === "node_modules" &&
|
|
1252
|
+
if (path8.basename(parent) === "node_modules" && existsSync6(path8.join(parent, "react"))) {
|
|
984
1253
|
return parent;
|
|
985
1254
|
}
|
|
986
1255
|
dir = parent;
|
|
@@ -1064,8 +1333,8 @@ async function createViteConfig(options) {
|
|
|
1064
1333
|
return next();
|
|
1065
1334
|
}
|
|
1066
1335
|
const indexPath = path8.join(srcRoot2, "theme/index.html");
|
|
1067
|
-
if (
|
|
1068
|
-
server.transformIndexHtml(req.url,
|
|
1336
|
+
if (existsSync6(indexPath)) {
|
|
1337
|
+
server.transformIndexHtml(req.url, readFileSync6(indexPath, "utf-8")).then((html) => {
|
|
1069
1338
|
res.setHeader("Content-Type", "text/html");
|
|
1070
1339
|
res.end(html);
|
|
1071
1340
|
}).catch(next);
|
|
@@ -1093,34 +1362,110 @@ async function createViteConfig(options) {
|
|
|
1093
1362
|
const urlPath = req.url?.split("?")[0] || "";
|
|
1094
1363
|
if (urlPath === "/_preview-runtime") {
|
|
1095
1364
|
const templatePath = path8.join(srcRoot2, "preview-runtime/template.html");
|
|
1096
|
-
if (
|
|
1097
|
-
const html =
|
|
1365
|
+
if (existsSync6(templatePath)) {
|
|
1366
|
+
const html = readFileSync6(templatePath, "utf-8");
|
|
1098
1367
|
res.setHeader("Content-Type", "text/html");
|
|
1099
1368
|
res.end(html);
|
|
1100
1369
|
return;
|
|
1101
1370
|
}
|
|
1102
1371
|
}
|
|
1103
1372
|
if (urlPath.startsWith("/_preview-config/")) {
|
|
1104
|
-
const
|
|
1373
|
+
const pathAfterConfig = decodeURIComponent(urlPath.slice("/_preview-config/".length));
|
|
1105
1374
|
const previewsDir = path8.join(rootDir, "previews");
|
|
1106
|
-
const
|
|
1107
|
-
if (
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
res.setHeader("Content-Type", "application/json");
|
|
1116
|
-
res.end(JSON.stringify(config2));
|
|
1375
|
+
const multiTypeMatch = pathAfterConfig.match(/^(components|screens|flows|atlas)\/(.+)$/);
|
|
1376
|
+
if (multiTypeMatch) {
|
|
1377
|
+
const [, type, name] = multiTypeMatch;
|
|
1378
|
+
const configPathYaml = path8.join(previewsDir, type, name, "index.yaml");
|
|
1379
|
+
const configPathYml = path8.join(previewsDir, type, name, "index.yml");
|
|
1380
|
+
const configPath = existsSync6(configPathYaml) ? configPathYaml : configPathYml;
|
|
1381
|
+
if (!configPath.startsWith(previewsDir)) {
|
|
1382
|
+
res.statusCode = 403;
|
|
1383
|
+
res.end("Forbidden");
|
|
1117
1384
|
return;
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1385
|
+
}
|
|
1386
|
+
if (existsSync6(configPath)) {
|
|
1387
|
+
try {
|
|
1388
|
+
if (type === "flows") {
|
|
1389
|
+
const flow = await parseFlowDefinition(configPath);
|
|
1390
|
+
if (flow) {
|
|
1391
|
+
res.setHeader("Content-Type", "application/json");
|
|
1392
|
+
res.end(JSON.stringify(flow));
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
} else if (type === "atlas") {
|
|
1396
|
+
const atlas = await parseAtlasDefinition(configPath);
|
|
1397
|
+
if (atlas) {
|
|
1398
|
+
res.setHeader("Content-Type", "application/json");
|
|
1399
|
+
res.end(JSON.stringify(atlas));
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
} else {
|
|
1403
|
+
const previewDir = path8.join(previewsDir, type, name);
|
|
1404
|
+
const config2 = await buildPreviewConfig(previewDir);
|
|
1405
|
+
res.setHeader("Content-Type", "application/json");
|
|
1406
|
+
res.end(JSON.stringify(config2));
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
res.statusCode = 400;
|
|
1410
|
+
res.end(JSON.stringify({ error: "Invalid config format" }));
|
|
1411
|
+
return;
|
|
1412
|
+
} catch (err) {
|
|
1413
|
+
console.error("Error building preview config:", err);
|
|
1414
|
+
res.statusCode = 500;
|
|
1415
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
} else {
|
|
1420
|
+
const previewDir = path8.resolve(previewsDir, pathAfterConfig);
|
|
1421
|
+
if (!previewDir.startsWith(previewsDir)) {
|
|
1422
|
+
res.statusCode = 403;
|
|
1423
|
+
res.end("Forbidden");
|
|
1122
1424
|
return;
|
|
1123
1425
|
}
|
|
1426
|
+
if (existsSync6(previewDir)) {
|
|
1427
|
+
try {
|
|
1428
|
+
const config2 = await buildPreviewConfig(previewDir);
|
|
1429
|
+
res.setHeader("Content-Type", "application/json");
|
|
1430
|
+
res.end(JSON.stringify(config2));
|
|
1431
|
+
return;
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
console.error("Error building preview config:", err);
|
|
1434
|
+
res.statusCode = 500;
|
|
1435
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
if (urlPath.match(/^\/_preview\/(components|screens|flows|atlas)\/[^/]+\/?$/)) {
|
|
1442
|
+
const routeMatch = urlPath.match(/^\/_preview\/(\w+)\/([^/]+)\/?$/);
|
|
1443
|
+
if (routeMatch) {
|
|
1444
|
+
const [, type, name] = routeMatch;
|
|
1445
|
+
const singularType = TYPE_SINGULAR[type] || type;
|
|
1446
|
+
const shellHtml = `<!DOCTYPE html>
|
|
1447
|
+
<html>
|
|
1448
|
+
<head>
|
|
1449
|
+
<meta charset="UTF-8">
|
|
1450
|
+
<title>Preview: ${name}</title>
|
|
1451
|
+
<script type="module">
|
|
1452
|
+
import { PreviewRouter } from '@prev/theme/previews'
|
|
1453
|
+
import { createRoot } from 'react-dom/client'
|
|
1454
|
+
import React from 'react'
|
|
1455
|
+
|
|
1456
|
+
createRoot(document.getElementById('root')).render(
|
|
1457
|
+
React.createElement(PreviewRouter, { type: '${singularType}', name: '${name}' })
|
|
1458
|
+
)
|
|
1459
|
+
</script>
|
|
1460
|
+
</head>
|
|
1461
|
+
<body>
|
|
1462
|
+
<div id="root"></div>
|
|
1463
|
+
</body>
|
|
1464
|
+
</html>`;
|
|
1465
|
+
const transformed = await server.transformIndexHtml(req.url, shellHtml);
|
|
1466
|
+
res.setHeader("Content-Type", "text/html");
|
|
1467
|
+
res.end(transformed);
|
|
1468
|
+
return;
|
|
1124
1469
|
}
|
|
1125
1470
|
}
|
|
1126
1471
|
if (urlPath.startsWith("/_preview/")) {
|
|
@@ -1132,9 +1477,9 @@ async function createViteConfig(options) {
|
|
|
1132
1477
|
if (!htmlPath.startsWith(previewsDir)) {
|
|
1133
1478
|
return next();
|
|
1134
1479
|
}
|
|
1135
|
-
if (
|
|
1480
|
+
if (existsSync6(htmlPath)) {
|
|
1136
1481
|
try {
|
|
1137
|
-
let html =
|
|
1482
|
+
let html = readFileSync6(htmlPath, "utf-8");
|
|
1138
1483
|
const previewBase = `/_preview/${previewName}/`;
|
|
1139
1484
|
html = html.replace(/(src|href)=["']\.\/([^"']+)["']/g, `$1="${previewBase}$2"`);
|
|
1140
1485
|
const transformed = await server.transformIndexHtml(req.url, html);
|
|
@@ -1261,7 +1606,7 @@ async function findAvailablePort(minPort, maxPort) {
|
|
|
1261
1606
|
|
|
1262
1607
|
// src/vite/start.ts
|
|
1263
1608
|
import { exec } from "child_process";
|
|
1264
|
-
import { existsSync as
|
|
1609
|
+
import { existsSync as existsSync7, rmSync as rmSync3, copyFileSync } from "fs";
|
|
1265
1610
|
import path9 from "path";
|
|
1266
1611
|
function printWelcome(type) {
|
|
1267
1612
|
console.log();
|
|
@@ -1298,12 +1643,12 @@ function clearCache(rootDir) {
|
|
|
1298
1643
|
const viteCacheDir = path9.join(rootDir, ".vite");
|
|
1299
1644
|
const nodeModulesVite = path9.join(rootDir, "node_modules", ".vite");
|
|
1300
1645
|
let cleared = 0;
|
|
1301
|
-
if (
|
|
1302
|
-
|
|
1646
|
+
if (existsSync7(viteCacheDir)) {
|
|
1647
|
+
rmSync3(viteCacheDir, { recursive: true });
|
|
1303
1648
|
cleared++;
|
|
1304
1649
|
}
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1650
|
+
if (existsSync7(nodeModulesVite)) {
|
|
1651
|
+
rmSync3(nodeModulesVite, { recursive: true });
|
|
1307
1652
|
cleared++;
|
|
1308
1653
|
}
|
|
1309
1654
|
if (cleared === 0) {
|
|
@@ -1414,7 +1759,7 @@ async function buildSite(rootDir, options = {}) {
|
|
|
1414
1759
|
base: options.base,
|
|
1415
1760
|
debug: options.debug
|
|
1416
1761
|
});
|
|
1417
|
-
await
|
|
1762
|
+
await build3(config);
|
|
1418
1763
|
const debugCollector = getDebugCollector();
|
|
1419
1764
|
if (debugCollector) {
|
|
1420
1765
|
debugCollector.startPhase("buildComplete");
|
|
@@ -1424,7 +1769,7 @@ async function buildSite(rootDir, options = {}) {
|
|
|
1424
1769
|
const distDir = path9.join(rootDir, "dist");
|
|
1425
1770
|
const indexPath = path9.join(distDir, "index.html");
|
|
1426
1771
|
const notFoundPath = path9.join(distDir, "404.html");
|
|
1427
|
-
if (
|
|
1772
|
+
if (existsSync7(indexPath)) {
|
|
1428
1773
|
copyFileSync(indexPath, notFoundPath);
|
|
1429
1774
|
}
|
|
1430
1775
|
console.log();
|
|
@@ -1503,14 +1848,14 @@ async function cleanCache(options) {
|
|
|
1503
1848
|
}
|
|
1504
1849
|
|
|
1505
1850
|
// src/cli.ts
|
|
1506
|
-
import
|
|
1851
|
+
import yaml3 from "js-yaml";
|
|
1507
1852
|
function getVersion() {
|
|
1508
1853
|
try {
|
|
1509
|
-
let dir = path11.dirname(
|
|
1854
|
+
let dir = path11.dirname(fileURLToPath4(import.meta.url));
|
|
1510
1855
|
for (let i = 0;i < 5; i++) {
|
|
1511
1856
|
const pkgPath = path11.join(dir, "package.json");
|
|
1512
|
-
if (
|
|
1513
|
-
const pkg = JSON.parse(
|
|
1857
|
+
if (existsSync8(pkgPath)) {
|
|
1858
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
|
|
1514
1859
|
if (pkg.name === "prev-cli")
|
|
1515
1860
|
return pkg.version;
|
|
1516
1861
|
}
|
|
@@ -1637,21 +1982,21 @@ async function clearViteCache(rootDir2) {
|
|
|
1637
1982
|
let cleared = 0;
|
|
1638
1983
|
try {
|
|
1639
1984
|
const prevCacheDir = await getCacheDir(rootDir2);
|
|
1640
|
-
if (
|
|
1641
|
-
|
|
1985
|
+
if (existsSync8(prevCacheDir)) {
|
|
1986
|
+
rmSync4(prevCacheDir, { recursive: true });
|
|
1642
1987
|
cleared++;
|
|
1643
1988
|
console.log(` ✓ Removed ${prevCacheDir}`);
|
|
1644
1989
|
}
|
|
1645
1990
|
} catch {}
|
|
1646
1991
|
const viteCacheDir = path11.join(rootDir2, ".vite");
|
|
1647
1992
|
const nodeModulesVite = path11.join(rootDir2, "node_modules", ".vite");
|
|
1648
|
-
if (
|
|
1649
|
-
|
|
1993
|
+
if (existsSync8(viteCacheDir)) {
|
|
1994
|
+
rmSync4(viteCacheDir, { recursive: true });
|
|
1650
1995
|
cleared++;
|
|
1651
1996
|
console.log(` ✓ Removed .vite/`);
|
|
1652
1997
|
}
|
|
1653
|
-
if (
|
|
1654
|
-
|
|
1998
|
+
if (existsSync8(nodeModulesVite)) {
|
|
1999
|
+
rmSync4(nodeModulesVite, { recursive: true });
|
|
1655
2000
|
cleared++;
|
|
1656
2001
|
console.log(` ✓ Removed node_modules/.vite/`);
|
|
1657
2002
|
}
|
|
@@ -1678,7 +2023,7 @@ function handleConfig(rootDir2, subcommand) {
|
|
|
1678
2023
|
console.log(` File: (none - using defaults)
|
|
1679
2024
|
`);
|
|
1680
2025
|
}
|
|
1681
|
-
const yamlOutput =
|
|
2026
|
+
const yamlOutput = yaml3.dump(config, {
|
|
1682
2027
|
indent: 2,
|
|
1683
2028
|
lineWidth: -1,
|
|
1684
2029
|
quotingType: '"',
|
|
@@ -1732,7 +2077,7 @@ order: {}
|
|
|
1732
2077
|
# - "getting-started.md"
|
|
1733
2078
|
# - "guides/"
|
|
1734
2079
|
`;
|
|
1735
|
-
|
|
2080
|
+
writeFileSync6(targetPath, configContent, "utf-8");
|
|
1736
2081
|
console.log(`
|
|
1737
2082
|
✨ Created ${targetPath}
|
|
1738
2083
|
`);
|
|
@@ -1756,11 +2101,11 @@ Available subcommands: show, init, path`);
|
|
|
1756
2101
|
}
|
|
1757
2102
|
function createPreview(rootDir2, name) {
|
|
1758
2103
|
const previewDir = path11.join(rootDir2, "previews", name);
|
|
1759
|
-
if (
|
|
2104
|
+
if (existsSync8(previewDir)) {
|
|
1760
2105
|
console.error(`Preview "${name}" already exists at: ${previewDir}`);
|
|
1761
2106
|
process.exit(1);
|
|
1762
2107
|
}
|
|
1763
|
-
|
|
2108
|
+
mkdirSync4(previewDir, { recursive: true });
|
|
1764
2109
|
const appTsx = `import { useState } from 'react'
|
|
1765
2110
|
import './styles.css'
|
|
1766
2111
|
|
|
@@ -1881,8 +2226,8 @@ export default function App() {
|
|
|
1881
2226
|
.dark\\:text-white { color: #fff; }
|
|
1882
2227
|
}
|
|
1883
2228
|
`;
|
|
1884
|
-
|
|
1885
|
-
|
|
2229
|
+
writeFileSync6(path11.join(previewDir, "App.tsx"), appTsx);
|
|
2230
|
+
writeFileSync6(path11.join(previewDir, "styles.css"), stylesCss);
|
|
1886
2231
|
console.log(`
|
|
1887
2232
|
✨ Created preview: previews/${name}/
|
|
1888
2233
|
|