create-vista-app 0.2.16 → 0.3.2
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/bin/cli.js +535 -511
- package/bin/flash-template/app/index.tsx +86 -86
- package/bin/flash-template/app/root.tsx +35 -35
- package/package.json +3 -3
- package/template/README.md +46 -86
- package/template/app/globals.css +70 -70
- package/template/app/index.tsx +71 -71
- package/template/app/root.tsx +35 -35
- package/template/{utils → components}/theme-toggle.tsx +49 -49
- package/template/deploy/.dockerignore +10 -0
- package/template/deploy/Dockerfile +17 -0
- package/template/deploy/netlify.toml +7 -0
- package/template/deploy/render.yaml +16 -0
- package/template/deploy/vercel.json +16 -0
- package/template/deploy/wrangler.toml +3 -0
- package/template/tsconfig.json +4 -4
- package/template/vista-env.d.ts +12 -12
- package/template/vista.config.ts +21 -17
- package/template-typed/app/api/procedures/hello.ts +7 -7
- package/template-typed/app/api/routers/index.ts +8 -8
- package/template-typed/app/api/typed.ts +6 -6
- package/template-typed/vista.config.ts +21 -21
- package/LICENSE +0 -21
package/bin/cli.js
CHANGED
|
@@ -1,511 +1,535 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { execSync } = require('child_process');
|
|
6
|
-
const prompts = require('prompts');
|
|
7
|
-
|
|
8
|
-
const usageCommand = 'npx create-vista-app@latest <project-name>';
|
|
9
|
-
const SUPPORTED_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'];
|
|
10
|
-
|
|
11
|
-
// Detect which package manager invoked us (npm, pnpm, yarn, bun)
|
|
12
|
-
function normalizePackageManager(value) {
|
|
13
|
-
const normalized = String(value || '').trim().toLowerCase();
|
|
14
|
-
return SUPPORTED_PACKAGE_MANAGERS.includes(normalized) ? normalized : undefined;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function detectPackageManager(userAgent = process.env.npm_config_user_agent || '') {
|
|
18
|
-
const ua = String(userAgent || '');
|
|
19
|
-
if (ua.startsWith('pnpm')) return 'pnpm';
|
|
20
|
-
if (ua.startsWith('yarn')) return 'yarn';
|
|
21
|
-
if (ua.startsWith('bun')) return 'bun';
|
|
22
|
-
return 'npm';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function getExplicitPackageManagerFromArgs(args) {
|
|
26
|
-
const explicitValue = normalizePackageManager(getFlagValue('--package-manager'));
|
|
27
|
-
const explicitFlags = SUPPORTED_PACKAGE_MANAGERS.filter((manager) => args.includes(`--${manager}`));
|
|
28
|
-
|
|
29
|
-
if (explicitFlags.length > 1) {
|
|
30
|
-
console.error('Error: use only one package manager flag: --npm, --pnpm, --yarn, or --bun.');
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (getFlagValue('--package-manager') && !explicitValue) {
|
|
35
|
-
console.error(
|
|
36
|
-
`Error: unsupported package manager "${getFlagValue('--package-manager')}". Use npm, pnpm, yarn, or bun.`
|
|
37
|
-
);
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (explicitValue && explicitFlags.length > 0 && explicitFlags[0] !== explicitValue) {
|
|
42
|
-
console.error('Error: package manager flags conflict. Use only one package manager selector.');
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return explicitValue || explicitFlags[0];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const rawArgs = process.argv.slice(2);
|
|
50
|
-
const useTypedApiStarter = rawArgs.includes('--typed-api') || rawArgs.includes('--typed');
|
|
51
|
-
const skipInstall = rawArgs.includes('--skip-install');
|
|
52
|
-
const skipGit = rawArgs.includes('--no-git');
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
npx create-vista-app@latest
|
|
81
|
-
npx create-vista-app@latest
|
|
82
|
-
npx create-vista-app@latest my-vista-app --
|
|
83
|
-
npx create-vista-app@latest my-vista-app --
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (
|
|
140
|
-
if (
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (packageManager === '
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (packageManager === '
|
|
225
|
-
if (packageManager === '
|
|
226
|
-
return '
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
fs.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
.replace(/
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
.
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
.
|
|
386
|
-
.
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
.
|
|
395
|
-
.
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
.
|
|
401
|
-
|
|
402
|
-
.
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const prompts = require('prompts');
|
|
7
|
+
|
|
8
|
+
const usageCommand = 'npx create-vista-app@latest <project-name>';
|
|
9
|
+
const SUPPORTED_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'];
|
|
10
|
+
|
|
11
|
+
// Detect which package manager invoked us (npm, pnpm, yarn, bun)
|
|
12
|
+
function normalizePackageManager(value) {
|
|
13
|
+
const normalized = String(value || '').trim().toLowerCase();
|
|
14
|
+
return SUPPORTED_PACKAGE_MANAGERS.includes(normalized) ? normalized : undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function detectPackageManager(userAgent = process.env.npm_config_user_agent || '') {
|
|
18
|
+
const ua = String(userAgent || '');
|
|
19
|
+
if (ua.startsWith('pnpm')) return 'pnpm';
|
|
20
|
+
if (ua.startsWith('yarn')) return 'yarn';
|
|
21
|
+
if (ua.startsWith('bun')) return 'bun';
|
|
22
|
+
return 'npm';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getExplicitPackageManagerFromArgs(args) {
|
|
26
|
+
const explicitValue = normalizePackageManager(getFlagValue('--package-manager'));
|
|
27
|
+
const explicitFlags = SUPPORTED_PACKAGE_MANAGERS.filter((manager) => args.includes(`--${manager}`));
|
|
28
|
+
|
|
29
|
+
if (explicitFlags.length > 1) {
|
|
30
|
+
console.error('Error: use only one package manager flag: --npm, --pnpm, --yarn, or --bun.');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (getFlagValue('--package-manager') && !explicitValue) {
|
|
35
|
+
console.error(
|
|
36
|
+
`Error: unsupported package manager "${getFlagValue('--package-manager')}". Use npm, pnpm, yarn, or bun.`
|
|
37
|
+
);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (explicitValue && explicitFlags.length > 0 && explicitFlags[0] !== explicitValue) {
|
|
42
|
+
console.error('Error: package manager flags conflict. Use only one package manager selector.');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return explicitValue || explicitFlags[0];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const rawArgs = process.argv.slice(2);
|
|
50
|
+
const useTypedApiStarter = rawArgs.includes('--typed-api') || rawArgs.includes('--typed');
|
|
51
|
+
const skipInstall = rawArgs.includes('--skip-install');
|
|
52
|
+
const skipGit = rawArgs.includes('--no-git');
|
|
53
|
+
const includeDeployTemplates = !rawArgs.includes('--no-deploy-templates');
|
|
54
|
+
const assumeYes = rawArgs.includes('--yes') || rawArgs.includes('-y');
|
|
55
|
+
const canPrompt = !!(process.stdin.isTTY && process.stdout.isTTY);
|
|
56
|
+
const detectedPackageManager = detectPackageManager();
|
|
57
|
+
|
|
58
|
+
function getFlagValue(flag) {
|
|
59
|
+
const index = rawArgs.indexOf(flag);
|
|
60
|
+
if (index !== -1) {
|
|
61
|
+
const next = rawArgs[index + 1];
|
|
62
|
+
if (next && !next.startsWith('-')) return next;
|
|
63
|
+
}
|
|
64
|
+
const inline = rawArgs.find((arg) => arg.startsWith(`${flag}=`));
|
|
65
|
+
if (inline) return inline.slice(flag.length + 1);
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const explicitFlashpack = rawArgs.includes('--flashpack');
|
|
70
|
+
const explicitDefaultEngine = rawArgs.includes('--default-engine');
|
|
71
|
+
const explicitEngine = getFlagValue('--engine');
|
|
72
|
+
const explicitPackageManager = getExplicitPackageManagerFromArgs(rawArgs);
|
|
73
|
+
|
|
74
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
75
|
+
console.log(`
|
|
76
|
+
Usage:
|
|
77
|
+
${usageCommand} [--typed-api] [--skip-install] [--no-git] [--yes] [--no-deploy-templates] [--engine <default|flashpack>] [--flashpack] [--default-engine] [--package-manager <npm|pnpm|yarn|bun>] [--npm|--pnpm|--yarn|--bun]
|
|
78
|
+
|
|
79
|
+
Example:
|
|
80
|
+
npx create-vista-app@latest my-vista-app
|
|
81
|
+
npx create-vista-app@latest
|
|
82
|
+
npx create-vista-app@latest my-vista-app --typed-api
|
|
83
|
+
npx create-vista-app@latest my-vista-app --flashpack
|
|
84
|
+
npx create-vista-app@latest my-vista-app --package-manager pnpm
|
|
85
|
+
`);
|
|
86
|
+
process.exit(0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (explicitFlashpack && explicitDefaultEngine) {
|
|
90
|
+
console.error('Error: use only one of --flashpack or --default-engine.');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (explicitEngine && !['default', 'flashpack'].includes(explicitEngine)) {
|
|
95
|
+
console.error(`Error: unsupported engine "${explicitEngine}". Use "default" or "flashpack".`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function resolveProjectName() {
|
|
100
|
+
const args = rawArgs.filter((arg) => !arg.startsWith('-'));
|
|
101
|
+
if (args[0]) return args[0];
|
|
102
|
+
|
|
103
|
+
if (!canPrompt) {
|
|
104
|
+
return 'my-vista-app';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const response = await prompts({
|
|
108
|
+
type: 'text',
|
|
109
|
+
name: 'projectName',
|
|
110
|
+
message: 'Project name?',
|
|
111
|
+
initial: 'my-vista-app',
|
|
112
|
+
validate: (value) => {
|
|
113
|
+
const trimmed = String(value || '').trim();
|
|
114
|
+
if (!trimmed) return 'Project name is required.';
|
|
115
|
+
if (/[<>:"/\\|?*\x00-\x1F]/.test(trimmed)) return 'Use a valid folder name.';
|
|
116
|
+
return true;
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const value = String(response.projectName || '').trim();
|
|
121
|
+
if (!value) {
|
|
122
|
+
console.log('Aborted.');
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
async function confirmProceed(projectName, projectDir, engine, packageManager) {
|
|
128
|
+
if (assumeYes || !canPrompt) return true;
|
|
129
|
+
const response = await prompts({
|
|
130
|
+
type: 'confirm',
|
|
131
|
+
name: 'proceed',
|
|
132
|
+
message: `Create Vista app "${projectName}" in ${projectDir} (engine: ${engine}, package manager: ${packageManager})?`,
|
|
133
|
+
initial: true,
|
|
134
|
+
});
|
|
135
|
+
return response.proceed !== false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function resolveEngineChoice() {
|
|
139
|
+
if (explicitEngine) return explicitEngine;
|
|
140
|
+
if (explicitFlashpack) return 'flashpack';
|
|
141
|
+
if (explicitDefaultEngine) return 'default';
|
|
142
|
+
if (assumeYes || !canPrompt) return 'default';
|
|
143
|
+
|
|
144
|
+
const response = await prompts({
|
|
145
|
+
type: 'select',
|
|
146
|
+
name: 'engine',
|
|
147
|
+
message: 'Select engine',
|
|
148
|
+
choices: [
|
|
149
|
+
{
|
|
150
|
+
title: 'default (recommended)',
|
|
151
|
+
value: 'default',
|
|
152
|
+
description: 'Stable webpack-first path',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
title: 'flashpack',
|
|
156
|
+
value: 'flashpack',
|
|
157
|
+
description: 'Rust-first engine path',
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
initial: 0,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const value = String(response.engine || '').trim();
|
|
164
|
+
if (!value) {
|
|
165
|
+
console.log('Aborted.');
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function resolvePackageManagerChoice() {
|
|
172
|
+
if (explicitPackageManager) return explicitPackageManager;
|
|
173
|
+
if (assumeYes || !canPrompt) return detectedPackageManager;
|
|
174
|
+
|
|
175
|
+
const response = await prompts({
|
|
176
|
+
type: 'select',
|
|
177
|
+
name: 'packageManager',
|
|
178
|
+
message: 'Select package manager',
|
|
179
|
+
choices: [
|
|
180
|
+
{
|
|
181
|
+
title: 'npm',
|
|
182
|
+
value: 'npm',
|
|
183
|
+
description: 'Widely available default',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
title: 'pnpm',
|
|
187
|
+
value: 'pnpm',
|
|
188
|
+
description: 'Fast installs with shared store',
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
title: 'yarn',
|
|
192
|
+
value: 'yarn',
|
|
193
|
+
description: 'Classic Yarn workflow',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
title: 'bun',
|
|
197
|
+
value: 'bun',
|
|
198
|
+
description: 'Fast Bun-based install/runtime',
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
initial: Math.max(SUPPORTED_PACKAGE_MANAGERS.indexOf(detectedPackageManager), 0),
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const value = normalizePackageManager(response.packageManager);
|
|
205
|
+
if (!value) {
|
|
206
|
+
console.log('Aborted.');
|
|
207
|
+
process.exit(0);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return value;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function getInstallCommand(packageManager) {
|
|
214
|
+
if (packageManager === 'yarn') return 'yarn';
|
|
215
|
+
if (packageManager === 'bun') return 'bun install';
|
|
216
|
+
return `${packageManager} install`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function getRunCommand(packageManager) {
|
|
220
|
+
return packageManager === 'npm' ? 'npm run' : packageManager;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function getCreateCommand(packageManager) {
|
|
224
|
+
if (packageManager === 'pnpm') return 'pnpm create vista-app';
|
|
225
|
+
if (packageManager === 'yarn') return 'yarn create vista-app';
|
|
226
|
+
if (packageManager === 'bun') return 'bun create vista-app';
|
|
227
|
+
return 'npx create-vista-app@latest';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function copyRecursiveSync(src, dest) {
|
|
231
|
+
const exists = fs.existsSync(src);
|
|
232
|
+
const stats = exists && fs.statSync(src);
|
|
233
|
+
const isDirectory = exists && stats.isDirectory();
|
|
234
|
+
if (isDirectory) {
|
|
235
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
236
|
+
fs.readdirSync(src).forEach((childItemName) => {
|
|
237
|
+
copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
|
|
238
|
+
});
|
|
239
|
+
} else {
|
|
240
|
+
fs.copyFileSync(src, dest);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function injectEngineBlock(source, selectedEngine) {
|
|
245
|
+
// Prefer preserving existing formatting when an engine block already exists.
|
|
246
|
+
if (/\bengine\s*:\s*\{[\s\S]*?\bvariant\s*:\s*['"][^'"]+['"]/m.test(source)) {
|
|
247
|
+
return source.replace(
|
|
248
|
+
/(\bengine\s*:\s*\{[\s\S]*?\bvariant\s*:\s*['"])([^'"]+)(['"])/m,
|
|
249
|
+
`$1${selectedEngine}$3`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Replace existing scalar engine config
|
|
254
|
+
if (/\bengine\s*:\s*['"][^'"]+['"],?/m.test(source)) {
|
|
255
|
+
return source.replace(/\bengine\s*:\s*['"][^'"]+['"],?/m, `engine: '${selectedEngine}',`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Insert right after "const config = {"
|
|
259
|
+
const engineBlock = ` engine: {\n variant: '${selectedEngine}',\n },`;
|
|
260
|
+
const marker = 'const config = {';
|
|
261
|
+
const markerIndex = source.indexOf(marker);
|
|
262
|
+
if (markerIndex !== -1) {
|
|
263
|
+
const insertAt = markerIndex + marker.length;
|
|
264
|
+
return `${source.slice(0, insertAt)}\n${engineBlock}${source.slice(insertAt)}`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Fallback to a minimal config when template structure is unexpected
|
|
268
|
+
return `const config = {\n${engineBlock}\n};\n\nexport default config;\n`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function applyEngineToVistaConfig(projectDir, selectedEngine) {
|
|
272
|
+
const configPath = path.join(projectDir, 'vista.config.ts');
|
|
273
|
+
if (!fs.existsSync(configPath)) return;
|
|
274
|
+
|
|
275
|
+
const source = fs.readFileSync(configPath, 'utf8');
|
|
276
|
+
const patched = injectEngineBlock(source, selectedEngine);
|
|
277
|
+
fs.writeFileSync(configPath, patched);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function applyReadmeSelections(projectDir, selectedEngine, useTypedApi) {
|
|
281
|
+
const readmePath = path.join(projectDir, 'README.md');
|
|
282
|
+
if (!fs.existsSync(readmePath)) return;
|
|
283
|
+
|
|
284
|
+
const source = fs.readFileSync(readmePath, 'utf8');
|
|
285
|
+
const patched = source
|
|
286
|
+
.replace(/__VISTA_ENGINE__/g, selectedEngine)
|
|
287
|
+
.replace(/__VISTA_TYPED_API__/g, useTypedApi ? 'enabled' : 'disabled');
|
|
288
|
+
fs.writeFileSync(readmePath, patched);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function applyFlashpackStarterTheme(projectDir) {
|
|
292
|
+
const flashTemplateDir = path.join(__dirname, 'flash-template');
|
|
293
|
+
if (fs.existsSync(flashTemplateDir)) {
|
|
294
|
+
copyRecursiveSync(flashTemplateDir, projectDir);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function applyDeployTemplates(projectDir, options = {}) {
|
|
299
|
+
const deployTemplateDir = path.join(__dirname, '../template/deploy');
|
|
300
|
+
if (!fs.existsSync(deployTemplateDir)) return;
|
|
301
|
+
|
|
302
|
+
const includeAll = Boolean(options.all);
|
|
303
|
+
const defaultFiles = ['render.yaml', 'Dockerfile', '.dockerignore'];
|
|
304
|
+
const optionalFiles = ['wrangler.toml', 'netlify.toml', 'vercel.json'];
|
|
305
|
+
const filesToCopy = includeAll ? [...defaultFiles, ...optionalFiles] : defaultFiles;
|
|
306
|
+
|
|
307
|
+
for (const fileName of filesToCopy) {
|
|
308
|
+
const source = path.join(deployTemplateDir, fileName);
|
|
309
|
+
const target = path.join(projectDir, fileName);
|
|
310
|
+
if (fs.existsSync(source) && !fs.existsSync(target)) {
|
|
311
|
+
fs.copyFileSync(source, target);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function main() {
|
|
317
|
+
const useLocal = rawArgs.includes('--local');
|
|
318
|
+
const currentDir = process.cwd();
|
|
319
|
+
const projectName = await resolveProjectName();
|
|
320
|
+
const selectedEngine = await resolveEngineChoice();
|
|
321
|
+
const selectedPackageManager = await resolvePackageManagerChoice();
|
|
322
|
+
const projectDir = path.join(currentDir, projectName);
|
|
323
|
+
|
|
324
|
+
const proceed = await confirmProceed(
|
|
325
|
+
projectName,
|
|
326
|
+
projectDir,
|
|
327
|
+
selectedEngine,
|
|
328
|
+
selectedPackageManager
|
|
329
|
+
);
|
|
330
|
+
if (!proceed) {
|
|
331
|
+
console.log('Aborted.');
|
|
332
|
+
process.exit(0);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
console.log(`Creating a new Vista app in ${projectDir}...`);
|
|
336
|
+
|
|
337
|
+
// 1. Create Directory
|
|
338
|
+
if (fs.existsSync(projectDir)) {
|
|
339
|
+
console.error(`Error: Directory ${projectName} already exists.`);
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
342
|
+
fs.mkdirSync(projectDir);
|
|
343
|
+
|
|
344
|
+
// 2. Copy Template
|
|
345
|
+
const templateDir = path.join(__dirname, '../template');
|
|
346
|
+
copyRecursiveSync(templateDir, projectDir);
|
|
347
|
+
|
|
348
|
+
if (useTypedApiStarter) {
|
|
349
|
+
const typedTemplateDir = path.join(__dirname, '../template-typed');
|
|
350
|
+
copyRecursiveSync(typedTemplateDir, projectDir);
|
|
351
|
+
console.log('Added typed API starter files.');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
applyEngineToVistaConfig(projectDir, selectedEngine);
|
|
355
|
+
applyReadmeSelections(projectDir, selectedEngine, useTypedApiStarter);
|
|
356
|
+
if (selectedEngine === 'flashpack') {
|
|
357
|
+
applyFlashpackStarterTheme(projectDir);
|
|
358
|
+
}
|
|
359
|
+
if (includeDeployTemplates) {
|
|
360
|
+
applyDeployTemplates(projectDir, { all: rawArgs.includes('--deploy-templates-all') });
|
|
361
|
+
console.log('Added deployment templates (render.yaml, Dockerfile).');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
console.log('Scaffolding complete.');
|
|
365
|
+
|
|
366
|
+
// 3. Setup Dependencies (production-ready)
|
|
367
|
+
const packageJson = {
|
|
368
|
+
name: projectName,
|
|
369
|
+
version: '0.1.0',
|
|
370
|
+
scripts: {
|
|
371
|
+
dev: 'vista dev',
|
|
372
|
+
build: 'vista build',
|
|
373
|
+
start: 'vista start',
|
|
374
|
+
deploy: 'vista deploy',
|
|
375
|
+
},
|
|
376
|
+
dependencies: {
|
|
377
|
+
// Runtime dependencies
|
|
378
|
+
react: '^19.0.0',
|
|
379
|
+
'react-dom': '^19.0.0',
|
|
380
|
+
'react-server-dom-webpack': '^19.0.0',
|
|
381
|
+
vista: useLocal ? 'file:../packages/vista' : 'npm:@vistagenic/vista@0.3.2',
|
|
382
|
+
'lucide-react': '^0.468.0',
|
|
383
|
+
// CSS build (needed in production for vista build)
|
|
384
|
+
postcss: '^8.0.0',
|
|
385
|
+
tailwindcss: '^4.0.0',
|
|
386
|
+
'@tailwindcss/postcss': '^4.0.0',
|
|
387
|
+
'@swc-node/register': '^1.9.0',
|
|
388
|
+
'@swc/core': '^1.4.0',
|
|
389
|
+
},
|
|
390
|
+
devDependencies: {
|
|
391
|
+
typescript: '^5.0.0',
|
|
392
|
+
'@types/react': '^19.0.0',
|
|
393
|
+
'@types/react-dom': '^19.0.0',
|
|
394
|
+
webpack: '^5.90.0',
|
|
395
|
+
'postcss-cli': '^11.0.0',
|
|
396
|
+
tsx: '^4.7.0',
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
fs.writeFileSync(path.join(projectDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
401
|
+
|
|
402
|
+
// 4. Create .gitignore
|
|
403
|
+
const gitignoreContent = `# Dependencies
|
|
404
|
+
node_modules/
|
|
405
|
+
.pnpm-store/
|
|
406
|
+
|
|
407
|
+
# Build outputs
|
|
408
|
+
dist/
|
|
409
|
+
.vista/
|
|
410
|
+
.flash/
|
|
411
|
+
out/
|
|
412
|
+
|
|
413
|
+
# Rust artifacts
|
|
414
|
+
target/
|
|
415
|
+
*.node
|
|
416
|
+
|
|
417
|
+
# IDE
|
|
418
|
+
.idea/
|
|
419
|
+
.vscode/
|
|
420
|
+
*.swp
|
|
421
|
+
*.swo
|
|
422
|
+
|
|
423
|
+
# Environment
|
|
424
|
+
.env
|
|
425
|
+
.env.local
|
|
426
|
+
.env.development.local
|
|
427
|
+
.env.test.local
|
|
428
|
+
.env.production.local
|
|
429
|
+
|
|
430
|
+
# Logs
|
|
431
|
+
npm-debug.log*
|
|
432
|
+
yarn-debug.log*
|
|
433
|
+
yarn-error.log*
|
|
434
|
+
pnpm-debug.log*
|
|
435
|
+
|
|
436
|
+
# OS files
|
|
437
|
+
.DS_Store
|
|
438
|
+
Thumbs.db
|
|
439
|
+
|
|
440
|
+
# TypeScript
|
|
441
|
+
*.tsbuildinfo
|
|
442
|
+
|
|
443
|
+
# Testing
|
|
444
|
+
coverage/
|
|
445
|
+
|
|
446
|
+
# Misc
|
|
447
|
+
*.log
|
|
448
|
+
`;
|
|
449
|
+
|
|
450
|
+
fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignoreContent);
|
|
451
|
+
|
|
452
|
+
console.log('Created .gitignore');
|
|
453
|
+
|
|
454
|
+
// 5. Initialize Git Repository
|
|
455
|
+
if (!skipGit) {
|
|
456
|
+
try {
|
|
457
|
+
execSync('git init', { cwd: projectDir, stdio: 'pipe' });
|
|
458
|
+
execSync('git add .', { cwd: projectDir, stdio: 'pipe' });
|
|
459
|
+
execSync('git commit -m "Initial commit from create-vista-app"', {
|
|
460
|
+
cwd: projectDir,
|
|
461
|
+
stdio: 'pipe',
|
|
462
|
+
env: {
|
|
463
|
+
...process.env,
|
|
464
|
+
GIT_AUTHOR_NAME: 'Vista',
|
|
465
|
+
GIT_AUTHOR_EMAIL: 'vista@example.com',
|
|
466
|
+
GIT_COMMITTER_NAME: 'Vista',
|
|
467
|
+
GIT_COMMITTER_EMAIL: 'vista@example.com',
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
console.log('Initialized git repository with initial commit');
|
|
471
|
+
} catch (e) {
|
|
472
|
+
// Git might not be installed, that's okay
|
|
473
|
+
console.log('Note: Could not initialize git repository. You can do this manually with: git init');
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
console.log('Skipped git initialization (--no-git).');
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// 6. Install Dependencies
|
|
480
|
+
const installCmd = getInstallCommand(selectedPackageManager);
|
|
481
|
+
if (!skipInstall) {
|
|
482
|
+
console.log(
|
|
483
|
+
`\nInstalling dependencies with ${selectedPackageManager}... This may take a moment.\n`
|
|
484
|
+
);
|
|
485
|
+
try {
|
|
486
|
+
execSync(installCmd, { cwd: projectDir, stdio: 'inherit' });
|
|
487
|
+
console.log(`\n✓ Dependencies installed successfully!`);
|
|
488
|
+
} catch (e) {
|
|
489
|
+
console.log(
|
|
490
|
+
`\nNote: Could not install dependencies automatically. Run "${installCmd}" manually.`
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
} else {
|
|
494
|
+
console.log('\nSkipped dependency installation (--skip-install).');
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const runCmd = getRunCommand(selectedPackageManager);
|
|
498
|
+
const createCmd = getCreateCommand(selectedPackageManager);
|
|
499
|
+
|
|
500
|
+
console.log(`
|
|
501
|
+
✨ Success! Created ${projectName} at ${projectDir}
|
|
502
|
+
Engine: ${selectedEngine}
|
|
503
|
+
Package manager: ${selectedPackageManager}
|
|
504
|
+
|
|
505
|
+
Get started by running:
|
|
506
|
+
|
|
507
|
+
cd ${projectName}
|
|
508
|
+
${runCmd} dev
|
|
509
|
+
|
|
510
|
+
Create another app anytime with:
|
|
511
|
+
${createCmd} <project-name>
|
|
512
|
+
|
|
513
|
+
Happy Hacking! 🚀
|
|
514
|
+
`);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
module.exports = {
|
|
518
|
+
main,
|
|
519
|
+
detectPackageManager,
|
|
520
|
+
normalizePackageManager,
|
|
521
|
+
getInstallCommand,
|
|
522
|
+
getRunCommand,
|
|
523
|
+
getCreateCommand,
|
|
524
|
+
injectEngineBlock,
|
|
525
|
+
applyEngineToVistaConfig,
|
|
526
|
+
applyReadmeSelections,
|
|
527
|
+
applyFlashpackStarterTheme,
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
if (require.main === module) {
|
|
531
|
+
main().catch((error) => {
|
|
532
|
+
console.error('create-vista-app failed:', error);
|
|
533
|
+
process.exit(1);
|
|
534
|
+
});
|
|
535
|
+
}
|