create-vidra-app 0.1.5 → 0.1.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/README.md +9 -6
- package/dist/cli.js +520 -229
- package/dist/index.js +136 -56
- package/package.json +10 -1
- package/templates/react-vite/README.md +7 -3
- package/templates/react-vite/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import prompts2 from "prompts";
|
|
3
|
-
import chalk3 from "chalk";
|
|
4
3
|
import fs2 from "fs-extra";
|
|
5
4
|
import path2 from "path";
|
|
6
5
|
import { randomUUID } from "crypto";
|
|
@@ -26,7 +25,17 @@ var parseArgs = (argv) => {
|
|
|
26
25
|
const arg = argv[i];
|
|
27
26
|
if (arg.startsWith("--")) {
|
|
28
27
|
const [key, val] = arg.slice(2).split("=");
|
|
29
|
-
|
|
28
|
+
if (val !== void 0) {
|
|
29
|
+
args[key] = val;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const next = argv[i + 1];
|
|
33
|
+
if (next !== void 0 && !next.startsWith("--")) {
|
|
34
|
+
args[key] = next;
|
|
35
|
+
i++;
|
|
36
|
+
} else {
|
|
37
|
+
args[key] = true;
|
|
38
|
+
}
|
|
30
39
|
} else {
|
|
31
40
|
args._.push(arg);
|
|
32
41
|
}
|
|
@@ -36,10 +45,53 @@ var parseArgs = (argv) => {
|
|
|
36
45
|
|
|
37
46
|
// src/exec.ts
|
|
38
47
|
import { execSync } from "child_process";
|
|
48
|
+
|
|
49
|
+
// src/theme.ts
|
|
39
50
|
import chalk from "chalk";
|
|
40
|
-
var
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
var lime = chalk.hex("#c8f751");
|
|
52
|
+
var value = chalk.hex("#e8e8ec");
|
|
53
|
+
var dim = chalk.hex("#7a7a86");
|
|
54
|
+
var amber = chalk.hex("#ffcf5c");
|
|
55
|
+
var green = chalk.hex("#86d98f");
|
|
56
|
+
var red = chalk.hex("#ff8585");
|
|
57
|
+
var slate = chalk.hex("#a9b0bd");
|
|
58
|
+
var uiColor = chalk.hex("#6fd3e0");
|
|
59
|
+
var hostColor = chalk.hex("#a48ce8");
|
|
60
|
+
var GLYPH_CHAR = {
|
|
61
|
+
done: "\u2713",
|
|
62
|
+
active: "\u25B8",
|
|
63
|
+
error: "\u2717",
|
|
64
|
+
manual: "?",
|
|
65
|
+
plan: "\u25C6",
|
|
66
|
+
skip: "\u2298"
|
|
67
|
+
};
|
|
68
|
+
var GLYPH_COLOR = {
|
|
69
|
+
done: green,
|
|
70
|
+
active: lime,
|
|
71
|
+
error: red,
|
|
72
|
+
manual: amber,
|
|
73
|
+
plan: slate,
|
|
74
|
+
skip: slate
|
|
75
|
+
};
|
|
76
|
+
var glyph = (name) => GLYPH_COLOR[name](GLYPH_CHAR[name]);
|
|
77
|
+
var wordmark = () => lime("vidra");
|
|
78
|
+
var kv = (label, val, width = 9) => ` ${dim(label.padEnd(width))} ${value(val)}`;
|
|
79
|
+
var row = (opts) => {
|
|
80
|
+
const parts = [` ${glyph(opts.glyph)}`];
|
|
81
|
+
if (opts.label !== void 0) {
|
|
82
|
+
const padded = opts.labelWidth ? opts.label.padEnd(opts.labelWidth) : opts.label;
|
|
83
|
+
parts.push(value(padded));
|
|
84
|
+
}
|
|
85
|
+
if (opts.detail) parts.push(opts.detail);
|
|
86
|
+
return parts.join(" ");
|
|
87
|
+
};
|
|
88
|
+
var footer = (content) => ` ${content}`;
|
|
89
|
+
var fixLine = (cmd, label = "fix:") => ` ${amber(label)} ${lime(cmd)}`;
|
|
90
|
+
|
|
91
|
+
// src/exec.ts
|
|
92
|
+
var toText = (value2) => {
|
|
93
|
+
if (value2 == null) return "";
|
|
94
|
+
return Buffer.isBuffer(value2) ? value2.toString() : value2;
|
|
43
95
|
};
|
|
44
96
|
var formatProcessError = (error) => {
|
|
45
97
|
const err = error;
|
|
@@ -50,8 +102,8 @@ var exec = (cmd, cwd) => {
|
|
|
50
102
|
try {
|
|
51
103
|
execSync(cmd, { cwd, stdio: "pipe" });
|
|
52
104
|
} catch (e) {
|
|
53
|
-
console.error(
|
|
54
|
-
console.error(
|
|
105
|
+
console.error(row({ glyph: "error", detail: dim(`command failed: ${cmd}`) }));
|
|
106
|
+
console.error(dim(formatProcessError(e)));
|
|
55
107
|
process.exit(1);
|
|
56
108
|
}
|
|
57
109
|
};
|
|
@@ -123,7 +175,6 @@ var applyReplacements = (str, replacements) => {
|
|
|
123
175
|
// src/doctor.ts
|
|
124
176
|
import { execFileSync } from "child_process";
|
|
125
177
|
import prompts from "prompts";
|
|
126
|
-
import chalk2 from "chalk";
|
|
127
178
|
var DOTNET = process.platform === "win32" ? "dotnet.exe" : "dotnet";
|
|
128
179
|
var MAUI_DOCS = "https://learn.microsoft.com/dotnet/maui/get-started/installation";
|
|
129
180
|
var bufToStr = (v) => v == null ? "" : Buffer.isBuffer(v) ? v.toString() : v;
|
|
@@ -186,11 +237,16 @@ var isInteractive = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
|
186
237
|
var installWorkload = (csprojPath) => {
|
|
187
238
|
const args = csprojPath ? ["workload", "restore", csprojPath] : ["workload", "install", "maui"];
|
|
188
239
|
console.log();
|
|
189
|
-
console.log(` ${chalk2.dim(`Running: ${DOTNET} ${args.join(" ")}`)}`);
|
|
190
240
|
console.log(
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
241
|
+
row({
|
|
242
|
+
glyph: "active",
|
|
243
|
+
detail: `${dim("running")} ${value(`${DOTNET} ${args.join(" ")}`)}`
|
|
244
|
+
})
|
|
245
|
+
);
|
|
246
|
+
console.log(
|
|
247
|
+
footer(
|
|
248
|
+
dim("this can download several hundred MB and take a few minutes.")
|
|
249
|
+
)
|
|
194
250
|
);
|
|
195
251
|
console.log();
|
|
196
252
|
try {
|
|
@@ -198,13 +254,15 @@ var installWorkload = (csprojPath) => {
|
|
|
198
254
|
return true;
|
|
199
255
|
} catch {
|
|
200
256
|
console.error();
|
|
201
|
-
console.error(
|
|
257
|
+
console.error(row({ glyph: "error", label: "workload install failed" }));
|
|
202
258
|
console.error(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
259
|
+
footer(
|
|
260
|
+
dim(
|
|
261
|
+
"if this is a permissions error, your SDK is in a system location and needs elevation:"
|
|
262
|
+
)
|
|
263
|
+
)
|
|
206
264
|
);
|
|
207
|
-
console.error(
|
|
265
|
+
console.error(fixLine("sudo dotnet workload install maui"));
|
|
208
266
|
console.error();
|
|
209
267
|
return false;
|
|
210
268
|
}
|
|
@@ -213,9 +271,15 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
213
271
|
const dotnet = checkDotnetSdk();
|
|
214
272
|
if (dotnet.status === "missing") {
|
|
215
273
|
console.log();
|
|
216
|
-
console.log(
|
|
274
|
+
console.log(
|
|
275
|
+
row({
|
|
276
|
+
glyph: "error",
|
|
277
|
+
label: dotnet.name,
|
|
278
|
+
detail: dotnet.detail ? dim(dotnet.detail) : void 0
|
|
279
|
+
})
|
|
280
|
+
);
|
|
217
281
|
if (dotnet.fix) {
|
|
218
|
-
console.log(
|
|
282
|
+
console.log(fixLine(dotnet.fix));
|
|
219
283
|
}
|
|
220
284
|
return false;
|
|
221
285
|
}
|
|
@@ -223,7 +287,11 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
223
287
|
if (isMauiWorkloadInstalled()) return true;
|
|
224
288
|
console.log();
|
|
225
289
|
console.log(
|
|
226
|
-
|
|
290
|
+
row({
|
|
291
|
+
glyph: "error",
|
|
292
|
+
label: ".NET MAUI workload",
|
|
293
|
+
detail: dim("required but not installed")
|
|
294
|
+
})
|
|
227
295
|
);
|
|
228
296
|
const interactive = opts.interactive ?? isInteractive();
|
|
229
297
|
if (interactive) {
|
|
@@ -241,20 +309,25 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
241
309
|
}
|
|
242
310
|
if (install) {
|
|
243
311
|
if (installWorkload(opts.csprojPath) && isMauiWorkloadInstalled()) {
|
|
244
|
-
console.log(
|
|
312
|
+
console.log(
|
|
313
|
+
row({
|
|
314
|
+
glyph: "done",
|
|
315
|
+
label: ".NET MAUI workload",
|
|
316
|
+
detail: dim("installed")
|
|
317
|
+
})
|
|
318
|
+
);
|
|
245
319
|
return true;
|
|
246
320
|
}
|
|
247
321
|
return false;
|
|
248
322
|
}
|
|
249
323
|
}
|
|
250
|
-
console.log(
|
|
251
|
-
|
|
252
|
-
);
|
|
253
|
-
console.log(` ${chalk2.dim("docs:")} ${chalk2.cyan(MAUI_DOCS)}`);
|
|
324
|
+
console.log(fixLine("dotnet workload install maui", "run:"));
|
|
325
|
+
console.log(fixLine(MAUI_DOCS, "docs:"));
|
|
254
326
|
return false;
|
|
255
327
|
};
|
|
256
328
|
|
|
257
329
|
// src/index.ts
|
|
330
|
+
var note = (label, body) => ` ${dim(label.padEnd(7))} ${body}`;
|
|
258
331
|
var __dirname = path2.dirname(fileURLToPath(import.meta.url));
|
|
259
332
|
var CLI_ROOT = path2.resolve(__dirname, "..");
|
|
260
333
|
var TEMPLATES_DIR = path2.join(CLI_ROOT, "templates");
|
|
@@ -266,8 +339,9 @@ var VIDRA_VERSION = "0.1.0";
|
|
|
266
339
|
var SDK_VERSION = "0.1.0";
|
|
267
340
|
var main = async () => {
|
|
268
341
|
console.log();
|
|
269
|
-
console.log(
|
|
270
|
-
console.log(
|
|
342
|
+
console.log(` create-${lime("vidra")}-app`);
|
|
343
|
+
console.log(footer(dim("scaffold a new vidra application")));
|
|
344
|
+
console.log();
|
|
271
345
|
const args = parseArgs(process.argv);
|
|
272
346
|
let projectDir = args._[0];
|
|
273
347
|
let appId = args["app-id"];
|
|
@@ -303,19 +377,20 @@ var main = async () => {
|
|
|
303
377
|
}
|
|
304
378
|
const root = path2.resolve(projectDir);
|
|
305
379
|
if (fs2.existsSync(root) && fs2.readdirSync(root).length > 0) {
|
|
380
|
+
console.error();
|
|
306
381
|
console.error(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
)
|
|
382
|
+
row({
|
|
383
|
+
glyph: "error",
|
|
384
|
+
detail: dim(`directory "${projectDir}" already exists and is not empty`)
|
|
385
|
+
})
|
|
312
386
|
);
|
|
387
|
+
console.error();
|
|
313
388
|
process.exit(1);
|
|
314
389
|
}
|
|
315
390
|
console.log();
|
|
316
|
-
console.log(
|
|
317
|
-
console.log(
|
|
318
|
-
console.log(
|
|
391
|
+
console.log(kv("project", projectName));
|
|
392
|
+
console.log(kv("directory", root));
|
|
393
|
+
console.log(kv("app id", appId));
|
|
319
394
|
console.log();
|
|
320
395
|
const isMonorepo = fs2.existsSync(path2.join(LOCAL_SDK_DIR, "package.json"));
|
|
321
396
|
const localFeedExists = isMonorepo && fs2.existsSync(LOCAL_FEED_DIR);
|
|
@@ -335,42 +410,49 @@ var main = async () => {
|
|
|
335
410
|
};
|
|
336
411
|
const templateDir = path2.join(TEMPLATES_DIR, "react-vite");
|
|
337
412
|
await scaffoldDir(templateDir, root, replacements);
|
|
338
|
-
console.log(
|
|
413
|
+
console.log(row({ glyph: "active", detail: dim("creating solution\u2026") }));
|
|
339
414
|
exec(`dotnet new sln -n ${projectName} --force`, root);
|
|
340
415
|
const slnFile = fs2.existsSync(path2.join(root, `${projectName}.slnx`)) ? `${projectName}.slnx` : `${projectName}.sln`;
|
|
341
416
|
exec(
|
|
342
417
|
`dotnet sln ${slnFile} add src/${projectName}.Host/${projectName}.Host.csproj`,
|
|
343
418
|
root
|
|
344
419
|
);
|
|
345
|
-
console.log(
|
|
420
|
+
console.log(row({ glyph: "active", detail: dim("installing dependencies\u2026") }));
|
|
346
421
|
const uiDir = path2.join(root, "ui");
|
|
347
422
|
const rootNpmOk = tryExec("npm install", root);
|
|
348
423
|
const uiNpmOk = tryExec("npm install", uiDir);
|
|
349
424
|
const npmOk = rootNpmOk && uiNpmOk;
|
|
350
425
|
console.log();
|
|
351
|
-
console.log(
|
|
426
|
+
console.log(
|
|
427
|
+
row({
|
|
428
|
+
glyph: "done",
|
|
429
|
+
detail: `${dim("your")} ${wordmark()} ${dim("app is ready")}`
|
|
430
|
+
})
|
|
431
|
+
);
|
|
432
|
+
console.log();
|
|
352
433
|
if (localFeedExists) {
|
|
353
|
-
console.log(
|
|
354
|
-
chalk3.dim(" NuGet:") + " local feed \u2192 " + chalk3.cyan(LOCAL_FEED_DIR)
|
|
355
|
-
);
|
|
434
|
+
console.log(note("nuget", `${dim("local feed \u2192")} ${value(LOCAL_FEED_DIR)}`));
|
|
356
435
|
} else if (isMonorepo) {
|
|
357
436
|
console.log(
|
|
358
|
-
|
|
437
|
+
row({
|
|
438
|
+
glyph: "manual",
|
|
439
|
+
detail: `${dim("local NuGet feed not found. run")} ${lime("./pack-local.sh")} ${dim("in the vidra repo, then update NuGet.Config.")}`
|
|
440
|
+
})
|
|
359
441
|
);
|
|
360
442
|
}
|
|
361
443
|
if (isMonorepo) {
|
|
362
|
-
console.log(
|
|
363
|
-
|
|
364
|
-
);
|
|
365
|
-
console.log(
|
|
366
|
-
chalk3.dim(" npm: ") + " create-vidra-app \u2192 " + chalk3.cyan(LOCAL_CLI_DIR)
|
|
367
|
-
);
|
|
444
|
+
console.log(note("npm", `${dim("@vidra-dev/sdk \u2192")} ${value(LOCAL_SDK_DIR)}`));
|
|
445
|
+
console.log(note("npm", `${dim("create-vidra-app \u2192")} ${value(LOCAL_CLI_DIR)}`));
|
|
368
446
|
}
|
|
369
447
|
console.log();
|
|
370
448
|
if (!npmOk) {
|
|
371
449
|
console.log(
|
|
372
|
-
|
|
450
|
+
row({
|
|
451
|
+
glyph: "manual",
|
|
452
|
+
detail: `${dim("npm install had errors. re-run")} ${lime("npm install")} ${dim("in the project root and in")} ${value("ui/")} ${dim("to retry.")}`
|
|
453
|
+
})
|
|
373
454
|
);
|
|
455
|
+
console.log();
|
|
374
456
|
}
|
|
375
457
|
const hostCsproj = path2.join(
|
|
376
458
|
root,
|
|
@@ -379,21 +461,19 @@ var main = async () => {
|
|
|
379
461
|
`${projectName}.Host.csproj`
|
|
380
462
|
);
|
|
381
463
|
const prereqsReady = await ensureMauiWorkload({ csprojPath: hostCsproj });
|
|
382
|
-
console.log(
|
|
383
|
-
console.log(` cd ${projectDir}`);
|
|
464
|
+
console.log(footer(dim("next steps")));
|
|
465
|
+
console.log(` ${value(`cd ${projectDir}`)}`);
|
|
384
466
|
console.log(
|
|
385
|
-
` npm run dev ${
|
|
467
|
+
` ${value("npm run dev")} ${dim("# starts vite + the MAUI host together")}`
|
|
386
468
|
);
|
|
387
469
|
if (!prereqsReady) {
|
|
388
470
|
console.log(
|
|
389
|
-
` ${
|
|
390
|
-
"vidra doctor"
|
|
391
|
-
)} ${chalk3.dim("to verify your setup first")}`
|
|
471
|
+
` ${dim("tip: run")} ${lime("npm run doctor")} ${dim("to verify your setup first")}`
|
|
392
472
|
);
|
|
393
473
|
}
|
|
394
474
|
console.log();
|
|
395
475
|
};
|
|
396
476
|
main().catch((e) => {
|
|
397
|
-
console.error(
|
|
477
|
+
console.error(row({ glyph: "error", detail: dim(e.message) }));
|
|
398
478
|
process.exit(1);
|
|
399
479
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-vidra-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Scaffold a new Vidra application (React + .NET MAUI)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,9 +21,18 @@
|
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"vidra",
|
|
24
|
+
"create-vidra-app",
|
|
25
|
+
"dotnet",
|
|
26
|
+
"csharp",
|
|
27
|
+
"dotnet-maui",
|
|
24
28
|
"maui",
|
|
25
29
|
"react",
|
|
30
|
+
"vue",
|
|
31
|
+
"svelte",
|
|
26
32
|
"cross-platform",
|
|
33
|
+
"desktop",
|
|
34
|
+
"electron-alternative",
|
|
35
|
+
"tauri-alternative",
|
|
27
36
|
"scaffold",
|
|
28
37
|
"cli"
|
|
29
38
|
],
|
|
@@ -14,12 +14,16 @@ A cross-platform application built with [Vidra](https://github.com/user/vidra)
|
|
|
14
14
|
Not sure if you're set up? Run:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
|
|
17
|
+
npm run doctor
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
It checks your .NET SDK, the MAUI workload, and (on macOS) Xcode, and prints the
|
|
21
21
|
exact command to fix anything that's missing.
|
|
22
22
|
|
|
23
|
+
> The `vidra` CLI ships as a local dev dependency of this project, so run it
|
|
24
|
+
> through npm (`npm run dev`, `npm run doctor`) or with `npx vidra <command>` —
|
|
25
|
+
> there is no global `vidra` command to install.
|
|
26
|
+
|
|
23
27
|
### Development
|
|
24
28
|
|
|
25
29
|
```bash
|
|
@@ -31,8 +35,8 @@ This starts the Vite dev server and launches the native host for the current OS.
|
|
|
31
35
|
To target a specific desktop platform explicitly:
|
|
32
36
|
|
|
33
37
|
```bash
|
|
34
|
-
vidra dev --target macos
|
|
35
|
-
vidra dev --target windows
|
|
38
|
+
npx vidra dev --target macos
|
|
39
|
+
npx vidra dev --target windows
|
|
36
40
|
```
|
|
37
41
|
|
|
38
42
|
If you want to run the pieces separately:
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
"dev": "vidra dev",
|
|
7
7
|
"dev:ui": "npm run dev --prefix ui",
|
|
8
8
|
"dev:host:macos": "vidra run --target macos",
|
|
9
|
-
"dev:host:windows": "vidra run --target windows"
|
|
9
|
+
"dev:host:windows": "vidra run --target windows",
|
|
10
|
+
"doctor": "vidra doctor"
|
|
10
11
|
},
|
|
11
12
|
"devDependencies": {
|
|
12
13
|
"create-vidra-app": "{{cliVersion}}"
|