prev-cli 0.24.5 → 0.24.7

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 CHANGED
@@ -15,68 +15,18 @@ import react from "@vitejs/plugin-react";
15
15
  import mdx from "@mdx-js/rollup";
16
16
  import remarkGfm from "remark-gfm";
17
17
  import rehypeHighlight from "rehype-highlight";
18
- import path9 from "path";
18
+ import path8 from "path";
19
+ import os from "os";
19
20
  import { fileURLToPath as fileURLToPath2 } from "url";
20
21
  import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
21
22
 
22
- // src/utils/cache.ts
23
- import { createHash } from "crypto";
24
- import { readdir, rm, stat, mkdir } from "fs/promises";
25
- import { exec } from "child_process";
26
- import { promisify } from "util";
27
- import path from "path";
28
- import os from "os";
29
- var execAsync = promisify(exec);
30
- var DEFAULT_CACHE_ROOT = path.join(os.homedir(), ".cache/prev");
31
- async function getCacheDir(rootDir, branch) {
32
- const resolvedBranch = branch ?? await getCurrentBranch(rootDir);
33
- const hash = createHash("sha1").update(`${rootDir}:${resolvedBranch}`).digest("hex").slice(0, 12);
34
- return path.join(DEFAULT_CACHE_ROOT, hash);
35
- }
36
- async function getCurrentBranch(rootDir) {
37
- try {
38
- const { stdout } = await execAsync("git branch --show-current", { cwd: rootDir });
39
- return stdout.trim() || "detached";
40
- } catch {
41
- return "no-git";
42
- }
43
- }
44
- async function cleanCache(options) {
45
- const cacheRoot = options.cacheRoot ?? DEFAULT_CACHE_ROOT;
46
- const maxAge = options.maxAgeDays * 24 * 60 * 60 * 1000;
47
- const now = Date.now();
48
- let dirs;
49
- try {
50
- dirs = await readdir(cacheRoot);
51
- } catch {
52
- return 0;
53
- }
54
- let removed = 0;
55
- for (const dir of dirs) {
56
- const fullPath = path.join(cacheRoot, dir);
57
- try {
58
- const info = await stat(fullPath);
59
- if (info.isDirectory() && now - info.mtimeMs > maxAge) {
60
- await rm(fullPath, { recursive: true });
61
- removed++;
62
- }
63
- } catch {}
64
- }
65
- return removed;
66
- }
67
- async function ensureCacheDir(rootDir) {
68
- const cacheDir = await getCacheDir(rootDir);
69
- await mkdir(cacheDir, { recursive: true });
70
- return cacheDir;
71
- }
72
-
73
23
  // src/vite/plugins/pages-plugin.ts
74
- import path3 from "path";
24
+ import path2 from "path";
75
25
 
76
26
  // src/vite/pages.ts
77
27
  import fg from "fast-glob";
78
28
  import { readFile } from "fs/promises";
79
- import path2 from "path";
29
+ import path from "path";
80
30
  import picomatch from "picomatch";
81
31
  function parseValue(value) {
82
32
  const trimmed = value.trim();
@@ -138,9 +88,9 @@ function fileToRoute(file) {
138
88
  normalizedFile = normalizedFile.slice(firstDir.length + 1) || normalizedFile;
139
89
  }
140
90
  const withoutExt = normalizedFile.replace(/\.mdx?$/, "");
141
- const basename = path2.basename(withoutExt).toLowerCase();
91
+ const basename = path.basename(withoutExt).toLowerCase();
142
92
  if (basename === "index" || basename === "readme") {
143
- const dir = path2.dirname(withoutExt);
93
+ const dir = path.dirname(withoutExt);
144
94
  if (dir === "." || dir === "") {
145
95
  return "/";
146
96
  }
@@ -182,7 +132,7 @@ async function scanPages(rootDir, options = {}) {
182
132
  const routeMap = new Map;
183
133
  for (const file of filteredFiles) {
184
134
  const route = fileToRoute(file);
185
- const basename = path2.basename(file, path2.extname(file)).toLowerCase();
135
+ const basename = path.basename(file, path.extname(file)).toLowerCase();
186
136
  const priority = basename === "index" ? 1 : basename === "readme" ? 2 : 0;
187
137
  const existing = routeMap.get(route);
188
138
  if (!existing || priority > 0 && priority < existing.priority) {
@@ -191,7 +141,7 @@ async function scanPages(rootDir, options = {}) {
191
141
  }
192
142
  const pages = [];
193
143
  for (const { file } of routeMap.values()) {
194
- const fullPath = path2.join(rootDir, file);
144
+ const fullPath = path.join(rootDir, file);
195
145
  const rawContent = await readFile(fullPath, "utf-8");
196
146
  const { frontmatter, content } = parseFrontmatter(rawContent);
197
147
  const title = extractTitle(content, file, frontmatter);
@@ -221,12 +171,12 @@ function extractTitle(content, file, frontmatter) {
221
171
  if (match) {
222
172
  return match[1].trim();
223
173
  }
224
- const basename = path2.basename(file, path2.extname(file)).toLowerCase();
174
+ const basename = path.basename(file, path.extname(file)).toLowerCase();
225
175
  if (isIndexFile(basename)) {
226
- const dirname = path2.dirname(file);
227
- return dirname === "." ? "Home" : capitalize(path2.basename(dirname));
176
+ const dirname = path.dirname(file);
177
+ return dirname === "." ? "Home" : capitalize(path.basename(dirname));
228
178
  }
229
- return capitalize(path2.basename(file, path2.extname(file)));
179
+ return capitalize(path.basename(file, path.extname(file)));
230
180
  }
231
181
  function capitalize(str) {
232
182
  return str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
@@ -295,7 +245,7 @@ function pagesPlugin(rootDir, options = {}) {
295
245
  if (id === RESOLVED_VIRTUAL_MODULES_ID) {
296
246
  const pages = await getPages();
297
247
  const imports = pages.map((page, i) => {
298
- const absolutePath = path3.join(rootDir, page.file);
248
+ const absolutePath = path2.join(rootDir, page.file);
299
249
  return `import * as _page${i} from ${JSON.stringify(absolutePath)};`;
300
250
  }).join(`
301
251
  `);
@@ -331,13 +281,13 @@ ${entries}
331
281
  }
332
282
 
333
283
  // src/vite/plugins/entry-plugin.ts
334
- import path4 from "path";
284
+ import path3 from "path";
335
285
  import { fileURLToPath } from "url";
336
286
  import { existsSync, readFileSync, writeFileSync, unlinkSync } from "fs";
337
287
  function findCliRoot() {
338
- let dir = path4.dirname(fileURLToPath(import.meta.url));
288
+ let dir = path3.dirname(fileURLToPath(import.meta.url));
339
289
  for (let i = 0;i < 10; i++) {
340
- const pkgPath = path4.join(dir, "package.json");
290
+ const pkgPath = path3.join(dir, "package.json");
341
291
  if (existsSync(pkgPath)) {
342
292
  try {
343
293
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
@@ -346,15 +296,15 @@ function findCliRoot() {
346
296
  }
347
297
  } catch {}
348
298
  }
349
- const parent = path4.dirname(dir);
299
+ const parent = path3.dirname(dir);
350
300
  if (parent === dir)
351
301
  break;
352
302
  dir = parent;
353
303
  }
354
- return path4.dirname(path4.dirname(fileURLToPath(import.meta.url)));
304
+ return path3.dirname(path3.dirname(fileURLToPath(import.meta.url)));
355
305
  }
356
306
  var cliRoot = findCliRoot();
357
- var srcRoot = path4.join(cliRoot, "src");
307
+ var srcRoot = path3.join(cliRoot, "src");
358
308
  function getHtml(entryPath, forBuild = false) {
359
309
  const scriptSrc = forBuild ? entryPath : `/@fs${entryPath}`;
360
310
  return `<!DOCTYPE html>
@@ -377,13 +327,13 @@ function getHtml(entryPath, forBuild = false) {
377
327
  </html>`;
378
328
  }
379
329
  function entryPlugin(rootDir) {
380
- const entryPath = path4.join(srcRoot, "theme/entry.tsx");
330
+ const entryPath = path3.join(srcRoot, "theme/entry.tsx");
381
331
  let tempHtmlPath = null;
382
332
  return {
383
333
  name: "prev-entry",
384
334
  config(config, { command }) {
385
335
  if (command === "build" && rootDir) {
386
- tempHtmlPath = path4.join(rootDir, "index.html");
336
+ tempHtmlPath = path3.join(rootDir, "index.html");
387
337
  writeFileSync(tempHtmlPath, getHtml(entryPath, true));
388
338
  const existingInput = config.build?.rollupOptions?.input || {};
389
339
  const inputObj = typeof existingInput === "string" ? { _original: existingInput } : Array.isArray(existingInput) ? Object.fromEntries(existingInput.map((f, i) => [`entry${i}`, f])) : existingInput;
@@ -430,10 +380,10 @@ function entryPlugin(rootDir) {
430
380
 
431
381
  // src/vite/previews.ts
432
382
  import fg2 from "fast-glob";
433
- import path5 from "path";
383
+ import path4 from "path";
434
384
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
435
385
  async function scanPreviews(rootDir) {
436
- const previewsDir = path5.join(rootDir, "previews");
386
+ const previewsDir = path4.join(rootDir, "previews");
437
387
  if (!existsSync2(previewsDir)) {
438
388
  return [];
439
389
  }
@@ -443,17 +393,17 @@ async function scanPreviews(rootDir) {
443
393
  });
444
394
  const previewDirs = new Map;
445
395
  for (const file of entryFiles) {
446
- const dir = path5.dirname(file);
396
+ const dir = path4.dirname(file);
447
397
  if (!previewDirs.has(dir)) {
448
398
  previewDirs.set(dir, file);
449
399
  }
450
400
  }
451
401
  return Array.from(previewDirs.entries()).map(([dir, file]) => {
452
- const name = dir === "." ? path5.basename(previewsDir) : dir;
402
+ const name = dir === "." ? path4.basename(previewsDir) : dir;
453
403
  return {
454
404
  name,
455
405
  route: `/_preview/${name}`,
456
- htmlPath: path5.join(previewsDir, file)
406
+ htmlPath: path4.join(previewsDir, file)
457
407
  };
458
408
  });
459
409
  }
@@ -463,8 +413,8 @@ async function scanPreviewFiles(previewDir) {
463
413
  ignore: ["node_modules/**", "dist/**"]
464
414
  });
465
415
  return files.map((file) => {
466
- const content = readFileSync2(path5.join(previewDir, file), "utf-8");
467
- const ext = path5.extname(file).slice(1);
416
+ const content = readFileSync2(path4.join(previewDir, file), "utf-8");
417
+ const ext = path4.extname(file).slice(1);
468
418
  return {
469
419
  path: file,
470
420
  content,
@@ -608,7 +558,7 @@ async function buildPreviewHtml(config) {
608
558
 
609
559
  // src/vite/plugins/previews-plugin.ts
610
560
  import { existsSync as existsSync3, mkdirSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
611
- import path6 from "path";
561
+ import path5 from "path";
612
562
  var VIRTUAL_MODULE_ID2 = "virtual:prev-previews";
613
563
  var RESOLVED_VIRTUAL_MODULE_ID2 = "\x00" + VIRTUAL_MODULE_ID2;
614
564
  function previewsPlugin(rootDir) {
@@ -641,10 +591,10 @@ function previewsPlugin(rootDir) {
641
591
  async closeBundle() {
642
592
  if (!isBuild)
643
593
  return;
644
- const distDir = path6.join(rootDir, "dist");
645
- const targetDir = path6.join(distDir, "_preview");
646
- const previewsDir = path6.join(rootDir, "previews");
647
- const oldPreviewsDir = path6.join(distDir, "previews");
594
+ const distDir = path5.join(rootDir, "dist");
595
+ const targetDir = path5.join(distDir, "_preview");
596
+ const previewsDir = path5.join(rootDir, "previews");
597
+ const oldPreviewsDir = path5.join(distDir, "previews");
648
598
  if (existsSync3(oldPreviewsDir)) {
649
599
  rmSync(oldPreviewsDir, { recursive: true });
650
600
  }
@@ -657,7 +607,7 @@ function previewsPlugin(rootDir) {
657
607
  console.log(`
658
608
  Building ${previews.length} preview(s)...`);
659
609
  for (const preview of previews) {
660
- const previewDir = path6.join(previewsDir, preview.name);
610
+ const previewDir = path5.join(previewsDir, preview.name);
661
611
  try {
662
612
  const config = await buildPreviewConfig(previewDir);
663
613
  const result = await buildPreviewHtml(config);
@@ -665,9 +615,9 @@ function previewsPlugin(rootDir) {
665
615
  console.error(` ✗ ${preview.name}: ${result.error}`);
666
616
  continue;
667
617
  }
668
- const outputDir = path6.join(targetDir, preview.name);
618
+ const outputDir = path5.join(targetDir, preview.name);
669
619
  mkdirSync(outputDir, { recursive: true });
670
- writeFileSync2(path6.join(outputDir, "index.html"), result.html);
620
+ writeFileSync2(path5.join(outputDir, "index.html"), result.html);
671
621
  console.log(` ✓ ${preview.name}`);
672
622
  } catch (err) {
673
623
  console.error(` ✗ ${preview.name}: ${err}`);
@@ -788,11 +738,11 @@ function validateConfig(raw) {
788
738
  }
789
739
  // src/config/loader.ts
790
740
  import { readFileSync as readFileSync3, existsSync as existsSync4, writeFileSync as writeFileSync3 } from "fs";
791
- import path7 from "path";
741
+ import path6 from "path";
792
742
  import yaml from "js-yaml";
793
743
  function findConfigFile(rootDir) {
794
- const yamlPath = path7.join(rootDir, ".prev.yaml");
795
- const ymlPath = path7.join(rootDir, ".prev.yml");
744
+ const yamlPath = path6.join(rootDir, ".prev.yaml");
745
+ const ymlPath = path6.join(rootDir, ".prev.yml");
796
746
  if (existsSync4(yamlPath))
797
747
  return yamlPath;
798
748
  if (existsSync4(ymlPath))
@@ -814,7 +764,7 @@ function loadConfig(rootDir) {
814
764
  }
815
765
  }
816
766
  function saveConfig(rootDir, config) {
817
- const configPath = findConfigFile(rootDir) || path7.join(rootDir, ".prev.yaml");
767
+ const configPath = findConfigFile(rootDir) || path6.join(rootDir, ".prev.yaml");
818
768
  const content = yaml.dump(config, {
819
769
  indent: 2,
820
770
  lineWidth: -1,
@@ -830,7 +780,7 @@ function updateOrder(rootDir, pathKey, order) {
830
780
  }
831
781
  // src/utils/debug.ts
832
782
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync4 } from "fs";
833
- import path8 from "path";
783
+ import path7 from "path";
834
784
 
835
785
  class DebugCollector {
836
786
  startTime;
@@ -889,7 +839,7 @@ class DebugCollector {
889
839
  }
890
840
  byDirectory[dir] = (byDirectory[dir] || 0) + 1;
891
841
  }
892
- const slowest = Object.entries(fileTimeAccum).map(([path9, totalMs]) => ({ path: path9, totalMs })).sort((a, b) => b.totalMs - a.totalMs).slice(0, 20);
842
+ const slowest = Object.entries(fileTimeAccum).map(([path8, totalMs]) => ({ path: path8, totalMs })).sort((a, b) => b.totalMs - a.totalMs).slice(0, 20);
893
843
  return {
894
844
  totalFiles: this.files.length,
895
845
  byDirectory,
@@ -908,11 +858,11 @@ class DebugCollector {
908
858
  files: this.files,
909
859
  summary: this.generateSummary()
910
860
  };
911
- const debugDir = path8.join(this.rootDir, ".prev-debug");
861
+ const debugDir = path7.join(this.rootDir, ".prev-debug");
912
862
  mkdirSync2(debugDir, { recursive: true });
913
863
  const date = new Date;
914
864
  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`;
915
- const filepath = path8.join(debugDir, filename);
865
+ const filepath = path7.join(debugDir, filename);
916
866
  writeFileSync4(filepath, JSON.stringify(report, null, 2));
917
867
  return filepath;
918
868
  }
@@ -981,9 +931,9 @@ function createFriendlyLogger() {
981
931
  };
982
932
  }
983
933
  function findCliRoot2() {
984
- let dir = path9.dirname(fileURLToPath2(import.meta.url));
934
+ let dir = path8.dirname(fileURLToPath2(import.meta.url));
985
935
  for (let i = 0;i < 10; i++) {
986
- const pkgPath = path9.join(dir, "package.json");
936
+ const pkgPath = path8.join(dir, "package.json");
987
937
  if (existsSync5(pkgPath)) {
988
938
  try {
989
939
  const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
@@ -992,24 +942,24 @@ function findCliRoot2() {
992
942
  }
993
943
  } catch {}
994
944
  }
995
- const parent = path9.dirname(dir);
945
+ const parent = path8.dirname(dir);
996
946
  if (parent === dir)
997
947
  break;
998
948
  dir = parent;
999
949
  }
1000
- return path9.dirname(path9.dirname(fileURLToPath2(import.meta.url)));
950
+ return path8.dirname(path8.dirname(fileURLToPath2(import.meta.url)));
1001
951
  }
1002
952
  function findNodeModules(cliRoot2) {
1003
- const localNodeModules = path9.join(cliRoot2, "node_modules");
1004
- if (existsSync5(path9.join(localNodeModules, "react"))) {
953
+ const localNodeModules = path8.join(cliRoot2, "node_modules");
954
+ if (existsSync5(path8.join(localNodeModules, "react"))) {
1005
955
  return localNodeModules;
1006
956
  }
1007
957
  let dir = cliRoot2;
1008
958
  for (let i = 0;i < 10; i++) {
1009
- const parent = path9.dirname(dir);
959
+ const parent = path8.dirname(dir);
1010
960
  if (parent === dir)
1011
961
  break;
1012
- if (path9.basename(parent) === "node_modules" && existsSync5(path9.join(parent, "react"))) {
962
+ if (path8.basename(parent) === "node_modules" && existsSync5(path8.join(parent, "react"))) {
1013
963
  return parent;
1014
964
  }
1015
965
  dir = parent;
@@ -1018,19 +968,19 @@ function findNodeModules(cliRoot2) {
1018
968
  }
1019
969
  var cliRoot2 = findCliRoot2();
1020
970
  var cliNodeModules = findNodeModules(cliRoot2);
1021
- var srcRoot2 = path9.join(cliRoot2, "src");
971
+ var srcRoot2 = path8.join(cliRoot2, "src");
1022
972
  async function createViteConfig(options) {
1023
973
  const { rootDir, mode, port, include, base, debug } = options;
1024
- const cacheDir = await ensureCacheDir(rootDir);
1025
974
  const config = loadConfig(rootDir);
1026
975
  const debugCollector = debug ? createDebugCollector(rootDir) : null;
1027
976
  if (debugCollector) {
1028
977
  debugCollector.startPhase("configLoad");
1029
978
  }
979
+ const globalCacheDir = path8.join(os.homedir(), ".cache/prev/deps");
1030
980
  return {
1031
981
  root: rootDir,
1032
982
  mode,
1033
- cacheDir,
983
+ cacheDir: globalCacheDir,
1034
984
  base: base || "/",
1035
985
  customLogger: createFriendlyLogger(),
1036
986
  logLevel: mode === "production" ? "silent" : "info",
@@ -1043,8 +993,8 @@ async function createViteConfig(options) {
1043
993
  rehypePlugins: [rehypeHighlight],
1044
994
  providerImportSource: "@mdx-js/react",
1045
995
  include: [
1046
- path9.join(rootDir, "**/*.md"),
1047
- path9.join(rootDir, "**/*.mdx")
996
+ path8.join(rootDir, "**/*.md"),
997
+ path8.join(rootDir, "**/*.mdx")
1048
998
  ],
1049
999
  exclude: [
1050
1000
  "**/node_modules/**",
@@ -1092,7 +1042,7 @@ async function createViteConfig(options) {
1092
1042
  if (urlPath.startsWith("/__") || urlPath.startsWith("/@") || urlPath.startsWith("/node_modules") || urlPath.includes(".")) {
1093
1043
  return next();
1094
1044
  }
1095
- const indexPath = path9.join(srcRoot2, "theme/index.html");
1045
+ const indexPath = path8.join(srcRoot2, "theme/index.html");
1096
1046
  if (existsSync5(indexPath)) {
1097
1047
  server.transformIndexHtml(req.url, readFileSync4(indexPath, "utf-8")).then((html) => {
1098
1048
  res.setHeader("Content-Type", "text/html");
@@ -1110,8 +1060,8 @@ async function createViteConfig(options) {
1110
1060
  resolveId(id) {
1111
1061
  if (id.startsWith("/_preview/")) {
1112
1062
  const relativePath = id.slice("/_preview/".length);
1113
- const previewsDir = path9.join(rootDir, "previews");
1114
- const resolved = path9.resolve(previewsDir, relativePath);
1063
+ const previewsDir = path8.join(rootDir, "previews");
1064
+ const resolved = path8.resolve(previewsDir, relativePath);
1115
1065
  if (resolved.startsWith(previewsDir)) {
1116
1066
  return resolved;
1117
1067
  }
@@ -1121,7 +1071,7 @@ async function createViteConfig(options) {
1121
1071
  server.middlewares.use(async (req, res, next) => {
1122
1072
  const urlPath = req.url?.split("?")[0] || "";
1123
1073
  if (urlPath === "/_preview-runtime") {
1124
- const templatePath = path9.join(srcRoot2, "preview-runtime/template.html");
1074
+ const templatePath = path8.join(srcRoot2, "preview-runtime/template.html");
1125
1075
  if (existsSync5(templatePath)) {
1126
1076
  const html = readFileSync4(templatePath, "utf-8");
1127
1077
  res.setHeader("Content-Type", "text/html");
@@ -1131,8 +1081,8 @@ async function createViteConfig(options) {
1131
1081
  }
1132
1082
  if (urlPath.startsWith("/_preview-config/")) {
1133
1083
  const previewName = decodeURIComponent(urlPath.slice("/_preview-config/".length));
1134
- const previewsDir = path9.join(rootDir, "previews");
1135
- const previewDir = path9.resolve(previewsDir, previewName);
1084
+ const previewsDir = path8.join(rootDir, "previews");
1085
+ const previewDir = path8.resolve(previewsDir, previewName);
1136
1086
  if (!previewDir.startsWith(previewsDir)) {
1137
1087
  res.statusCode = 403;
1138
1088
  res.end("Forbidden");
@@ -1153,11 +1103,11 @@ async function createViteConfig(options) {
1153
1103
  }
1154
1104
  }
1155
1105
  if (urlPath.startsWith("/_preview/")) {
1156
- const isHtmlRequest = !path9.extname(urlPath) || urlPath.endsWith("/");
1106
+ const isHtmlRequest = !path8.extname(urlPath) || urlPath.endsWith("/");
1157
1107
  if (isHtmlRequest) {
1158
1108
  const previewName = decodeURIComponent(urlPath.slice("/_preview/".length).replace(/\/$/, ""));
1159
- const previewsDir = path9.join(rootDir, "previews");
1160
- const htmlPath = path9.resolve(previewsDir, previewName, "index.html");
1109
+ const previewsDir = path8.join(rootDir, "previews");
1110
+ const htmlPath = path8.resolve(previewsDir, previewName, "index.html");
1161
1111
  if (!htmlPath.startsWith(previewsDir)) {
1162
1112
  return next();
1163
1113
  }
@@ -1184,15 +1134,15 @@ async function createViteConfig(options) {
1184
1134
  ],
1185
1135
  resolve: {
1186
1136
  alias: {
1187
- "@prev/ui": path9.join(srcRoot2, "ui"),
1188
- "@prev/theme": path9.join(srcRoot2, "theme"),
1189
- react: path9.join(cliNodeModules, "react"),
1190
- "react-dom": path9.join(cliNodeModules, "react-dom"),
1191
- "@tanstack/react-router": path9.join(cliNodeModules, "@tanstack/react-router"),
1192
- "@mdx-js/react": path9.join(cliNodeModules, "@mdx-js/react"),
1193
- mermaid: path9.join(cliNodeModules, "mermaid"),
1194
- dayjs: path9.join(cliNodeModules, "dayjs"),
1195
- "@terrastruct/d2": path9.join(cliNodeModules, "@terrastruct/d2")
1137
+ "@prev/ui": path8.join(srcRoot2, "ui"),
1138
+ "@prev/theme": path8.join(srcRoot2, "theme"),
1139
+ react: path8.join(cliNodeModules, "react"),
1140
+ "react-dom": path8.join(cliNodeModules, "react-dom"),
1141
+ "@tanstack/react-router": path8.join(cliNodeModules, "@tanstack/react-router"),
1142
+ "@mdx-js/react": path8.join(cliNodeModules, "@mdx-js/react"),
1143
+ mermaid: path8.join(cliNodeModules, "mermaid"),
1144
+ dayjs: path8.join(cliNodeModules, "dayjs"),
1145
+ "@terrastruct/d2": path8.join(cliNodeModules, "@terrastruct/d2")
1196
1146
  },
1197
1147
  dedupe: [
1198
1148
  "react",
@@ -1202,7 +1152,12 @@ async function createViteConfig(options) {
1202
1152
  },
1203
1153
  optimizeDeps: {
1204
1154
  noDiscovery: true,
1205
- include: [],
1155
+ holdUntilCrawlEnd: false,
1156
+ include: [
1157
+ "react-dom/client",
1158
+ "use-sync-external-store",
1159
+ "use-sync-external-store/shim/with-selector.js"
1160
+ ],
1206
1161
  exclude: [
1207
1162
  "virtual:prev-config",
1208
1163
  "virtual:prev-previews",
@@ -1222,8 +1177,8 @@ async function createViteConfig(options) {
1222
1177
  },
1223
1178
  warmup: {
1224
1179
  clientFiles: [
1225
- path9.join(srcRoot2, "theme/entry.tsx"),
1226
- path9.join(srcRoot2, "theme/styles.css")
1180
+ path8.join(srcRoot2, "theme/entry.tsx"),
1181
+ path8.join(srcRoot2, "theme/styles.css")
1227
1182
  ]
1228
1183
  }
1229
1184
  },
@@ -1232,12 +1187,12 @@ async function createViteConfig(options) {
1232
1187
  strictPort: false
1233
1188
  },
1234
1189
  build: {
1235
- outDir: path9.join(rootDir, "dist"),
1190
+ outDir: path8.join(rootDir, "dist"),
1236
1191
  reportCompressedSize: false,
1237
1192
  chunkSizeWarningLimit: 1e4,
1238
1193
  rollupOptions: {
1239
1194
  input: {
1240
- main: path9.join(srcRoot2, "theme/index.html")
1195
+ main: path8.join(srcRoot2, "theme/index.html")
1241
1196
  }
1242
1197
  }
1243
1198
  },
@@ -1280,9 +1235,9 @@ async function findAvailablePort(minPort, maxPort) {
1280
1235
  }
1281
1236
 
1282
1237
  // src/vite/start.ts
1283
- import { exec as exec2 } from "child_process";
1238
+ import { exec } from "child_process";
1284
1239
  import { existsSync as existsSync6, rmSync as rmSync2, copyFileSync } from "fs";
1285
- import path10 from "path";
1240
+ import path9 from "path";
1286
1241
  function printWelcome(type) {
1287
1242
  console.log();
1288
1243
  console.log(" ✨ prev");
@@ -1311,12 +1266,12 @@ function printReady() {
1311
1266
  function openBrowser(url) {
1312
1267
  const platform = process.platform;
1313
1268
  const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
1314
- exec2(`${cmd} ${url}`);
1269
+ exec(`${cmd} ${url}`);
1315
1270
  console.log(` ↗ Opened ${url}`);
1316
1271
  }
1317
1272
  function clearCache(rootDir) {
1318
- const viteCacheDir = path10.join(rootDir, ".vite");
1319
- const nodeModulesVite = path10.join(rootDir, "node_modules", ".vite");
1273
+ const viteCacheDir = path9.join(rootDir, ".vite");
1274
+ const nodeModulesVite = path9.join(rootDir, "node_modules", ".vite");
1320
1275
  let cleared = 0;
1321
1276
  if (existsSync6(viteCacheDir)) {
1322
1277
  rmSync2(viteCacheDir, { recursive: true });
@@ -1375,6 +1330,8 @@ async function startDev(rootDir, options = {}) {
1375
1330
  });
1376
1331
  const server = await createServer2(config);
1377
1332
  await server.listen();
1333
+ const warmupPort = server.config.server.port;
1334
+ fetch(`http://localhost:${warmupPort}/`).catch(() => {});
1378
1335
  const debugCollector = getDebugCollector();
1379
1336
  if (debugCollector) {
1380
1337
  debugCollector.startPhase("serverReady");
@@ -1439,9 +1396,9 @@ async function buildSite(rootDir, options = {}) {
1439
1396
  const reportPath = debugCollector.writeReport();
1440
1397
  console.log(` \uD83D\uDCCA Debug trace written to: ${reportPath}`);
1441
1398
  }
1442
- const distDir = path10.join(rootDir, "dist");
1443
- const indexPath = path10.join(distDir, "index.html");
1444
- const notFoundPath = path10.join(distDir, "404.html");
1399
+ const distDir = path9.join(rootDir, "dist");
1400
+ const indexPath = path9.join(distDir, "index.html");
1401
+ const notFoundPath = path9.join(distDir, "404.html");
1445
1402
  if (existsSync6(indexPath)) {
1446
1403
  copyFileSync(indexPath, notFoundPath);
1447
1404
  }
@@ -1474,6 +1431,52 @@ async function previewSite(rootDir, options = {}) {
1474
1431
  return server;
1475
1432
  }
1476
1433
 
1434
+ // src/utils/cache.ts
1435
+ import { createHash } from "crypto";
1436
+ import { readdir, rm, stat, mkdir } from "fs/promises";
1437
+ import { exec as exec2 } from "child_process";
1438
+ import { promisify } from "util";
1439
+ import path10 from "path";
1440
+ import os2 from "os";
1441
+ var execAsync = promisify(exec2);
1442
+ var DEFAULT_CACHE_ROOT = path10.join(os2.homedir(), ".cache/prev");
1443
+ async function getCacheDir(rootDir, branch) {
1444
+ const resolvedBranch = branch ?? await getCurrentBranch(rootDir);
1445
+ const hash = createHash("sha1").update(`${rootDir}:${resolvedBranch}`).digest("hex").slice(0, 12);
1446
+ return path10.join(DEFAULT_CACHE_ROOT, hash);
1447
+ }
1448
+ async function getCurrentBranch(rootDir) {
1449
+ try {
1450
+ const { stdout } = await execAsync("git branch --show-current", { cwd: rootDir });
1451
+ return stdout.trim() || "detached";
1452
+ } catch {
1453
+ return "no-git";
1454
+ }
1455
+ }
1456
+ async function cleanCache(options) {
1457
+ const cacheRoot = options.cacheRoot ?? DEFAULT_CACHE_ROOT;
1458
+ const maxAge = options.maxAgeDays * 24 * 60 * 60 * 1000;
1459
+ const now = Date.now();
1460
+ let dirs;
1461
+ try {
1462
+ dirs = await readdir(cacheRoot);
1463
+ } catch {
1464
+ return 0;
1465
+ }
1466
+ let removed = 0;
1467
+ for (const dir of dirs) {
1468
+ const fullPath = path10.join(cacheRoot, dir);
1469
+ try {
1470
+ const info = await stat(fullPath);
1471
+ if (info.isDirectory() && now - info.mtimeMs > maxAge) {
1472
+ await rm(fullPath, { recursive: true });
1473
+ removed++;
1474
+ }
1475
+ } catch {}
1476
+ }
1477
+ return removed;
1478
+ }
1479
+
1477
1480
  // src/cli.ts
1478
1481
  import yaml2 from "js-yaml";
1479
1482
  function getVersion() {
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { type VariantProps } from 'class-variance-authority';
3
3
  declare const buttonVariants: (props?: ({
4
- variant?: "default" | "link" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
4
+ variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
5
5
  size?: "default" | "sm" | "lg" | "icon" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prev-cli",
3
- "version": "0.24.5",
3
+ "version": "0.24.7",
4
4
  "description": "Transform MDX directories into beautiful documentation websites",
5
5
  "type": "module",
6
6
  "license": "MIT",