create-vidra-app 0.1.4 → 0.1.5
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 +228 -141
- package/dist/index.js +10 -2
- package/package.json +1 -1
- package/templates/react-vite/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// src/cli.ts
|
|
2
|
-
import
|
|
2
|
+
import chalk7 from "chalk";
|
|
3
3
|
|
|
4
4
|
// src/commands/build.ts
|
|
5
5
|
import path5 from "path";
|
|
6
6
|
import fs4 from "fs-extra";
|
|
7
|
-
import { execSync as
|
|
8
|
-
import
|
|
7
|
+
import { execSync as execSync3 } from "child_process";
|
|
8
|
+
import chalk5 from "chalk";
|
|
9
9
|
|
|
10
10
|
// src/utils.ts
|
|
11
11
|
var parseArgs = (argv) => {
|
|
@@ -22,10 +22,34 @@ var parseArgs = (argv) => {
|
|
|
22
22
|
return args;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
// src/exec.ts
|
|
26
|
+
import { execSync } from "child_process";
|
|
27
|
+
import chalk from "chalk";
|
|
28
|
+
var toText = (value) => {
|
|
29
|
+
if (value == null) return "";
|
|
30
|
+
return Buffer.isBuffer(value) ? value.toString() : value;
|
|
31
|
+
};
|
|
32
|
+
var formatProcessError = (error) => {
|
|
33
|
+
const err = error;
|
|
34
|
+
const combined = [toText(err.stderr), toText(err.stdout)].map((s) => s.trim()).filter((s) => s.length > 0).join("\n").trim();
|
|
35
|
+
return combined.length > 0 ? combined : err.message ?? String(error);
|
|
36
|
+
};
|
|
37
|
+
var formatBuildError = (error) => {
|
|
38
|
+
const raw = formatProcessError(error);
|
|
39
|
+
const lines = raw.split(/\r?\n/);
|
|
40
|
+
const errorLines = lines.filter(
|
|
41
|
+
(line) => /(:\s*error\b|\berror\s+[A-Z]{2,}\d+|Build FAILED|MSB\d{4}|NETSDK\d{4})/i.test(
|
|
42
|
+
line
|
|
43
|
+
)
|
|
44
|
+
);
|
|
45
|
+
const picked = errorLines.length > 0 ? errorLines : lines.filter((line) => line.trim().length > 0).slice(-30);
|
|
46
|
+
return picked.join("\n").trim();
|
|
47
|
+
};
|
|
48
|
+
|
|
25
49
|
// src/project.ts
|
|
26
50
|
import path from "path";
|
|
27
51
|
import fs from "fs-extra";
|
|
28
|
-
import
|
|
52
|
+
import chalk2 from "chalk";
|
|
29
53
|
var detectPlatform = () => {
|
|
30
54
|
switch (process.platform) {
|
|
31
55
|
case "darwin":
|
|
@@ -64,7 +88,7 @@ var detectProject = (cwd) => {
|
|
|
64
88
|
dir = parent;
|
|
65
89
|
}
|
|
66
90
|
console.error(
|
|
67
|
-
|
|
91
|
+
chalk2.red(
|
|
68
92
|
" Could not detect Vidra project. Run this command from your project root.\n Expected: package.json, ui/, src/<Name>.Host/<Name>.Host.csproj"
|
|
69
93
|
)
|
|
70
94
|
);
|
|
@@ -97,7 +121,7 @@ var readCsprojVersion = (csprojPath) => {
|
|
|
97
121
|
// src/targets/macos.ts
|
|
98
122
|
import path2 from "path";
|
|
99
123
|
import fs2 from "fs-extra";
|
|
100
|
-
import { execSync } from "child_process";
|
|
124
|
+
import { execSync as execSync2 } from "child_process";
|
|
101
125
|
import os from "os";
|
|
102
126
|
var macosTarget = {
|
|
103
127
|
name: "macos",
|
|
@@ -123,7 +147,7 @@ var macosTarget = {
|
|
|
123
147
|
if (fs2.existsSync(dmgPath)) {
|
|
124
148
|
fs2.removeSync(dmgPath);
|
|
125
149
|
}
|
|
126
|
-
|
|
150
|
+
execSync2(
|
|
127
151
|
`hdiutil create -volname "${volName}" -srcfolder "${staging}" -ov -format UDZO "${dmgPath}"`,
|
|
128
152
|
{ stdio: "pipe" }
|
|
129
153
|
);
|
|
@@ -137,41 +161,35 @@ var macosTarget = {
|
|
|
137
161
|
// src/signing.ts
|
|
138
162
|
import path3 from "path";
|
|
139
163
|
import { execFileSync } from "child_process";
|
|
140
|
-
import
|
|
164
|
+
import chalk3 from "chalk";
|
|
141
165
|
var signMacAppBundleIfPossible = (appBundle, options) => {
|
|
142
166
|
if (process.platform !== "darwin") return;
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
chalk2.yellow(
|
|
147
|
-
" No usable macOS signing identity found. The app will remain ad-hoc signed."
|
|
148
|
-
)
|
|
149
|
-
);
|
|
150
|
-
options.warn(
|
|
151
|
-
chalk2.yellow(
|
|
152
|
-
" Set VIDRA_MACOS_CODESIGN_KEY to override identity selection if needed."
|
|
153
|
-
)
|
|
154
|
-
);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
167
|
+
const identity = resolveMacCodeSigningIdentity();
|
|
168
|
+
const signWith = identity ?? "-";
|
|
169
|
+
const label = path3.basename(appBundle);
|
|
157
170
|
try {
|
|
158
171
|
execFileSync(
|
|
159
172
|
"codesign",
|
|
160
|
-
["--force", "--deep", "--sign",
|
|
173
|
+
["--force", "--deep", "--sign", signWith, appBundle],
|
|
161
174
|
{
|
|
162
175
|
stdio: options.verbose ? "inherit" : "pipe"
|
|
163
176
|
}
|
|
164
177
|
);
|
|
165
178
|
options.log(
|
|
166
|
-
` ${
|
|
179
|
+
identity ? ` ${chalk3.dim("Signing:")} ${chalk3.cyan(label)} ${chalk3.dim(`with ${identity}`)}` : ` ${chalk3.dim("Signing:")} ${chalk3.cyan(label)} ${chalk3.dim("ad-hoc (no developer identity)")}`
|
|
167
180
|
);
|
|
168
181
|
} catch (error) {
|
|
169
182
|
options.warn(
|
|
170
|
-
|
|
171
|
-
"
|
|
183
|
+
chalk3.yellow(
|
|
184
|
+
" Could not code-sign the macOS app bundle; it may fail to launch."
|
|
185
|
+
)
|
|
186
|
+
);
|
|
187
|
+
options.warn(
|
|
188
|
+
chalk3.yellow(
|
|
189
|
+
" Install Xcode or the Command Line Tools (provides `codesign`), or set VIDRA_MACOS_CODESIGN_KEY."
|
|
172
190
|
)
|
|
173
191
|
);
|
|
174
|
-
options.warn(
|
|
192
|
+
options.warn(chalk3.dim(formatExecError(error)));
|
|
175
193
|
}
|
|
176
194
|
};
|
|
177
195
|
var resolveMacCodeSigningIdentity = () => {
|
|
@@ -239,7 +257,7 @@ var windowsTarget = {
|
|
|
239
257
|
// src/doctor.ts
|
|
240
258
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
241
259
|
import prompts from "prompts";
|
|
242
|
-
import
|
|
260
|
+
import chalk4 from "chalk";
|
|
243
261
|
var DOTNET = process.platform === "win32" ? "dotnet.exe" : "dotnet";
|
|
244
262
|
var MAUI_DOCS = "https://learn.microsoft.com/dotnet/maui/get-started/installation";
|
|
245
263
|
var bufToStr = (v) => v == null ? "" : Buffer.isBuffer(v) ? v.toString() : v;
|
|
@@ -272,6 +290,11 @@ var looksLikeMissingWorkload = (output) => [
|
|
|
272
290
|
/maui-windows/i,
|
|
273
291
|
/to\s+install\s+the\s+.*workload/i
|
|
274
292
|
].some((re) => re.test(output));
|
|
293
|
+
var looksLikeMissingXcode = (output) => [
|
|
294
|
+
/valid\s+Xcode\s+installation\s+was\s+not\s+found/i,
|
|
295
|
+
/could\s+not\s+find\s+a\s+valid\s+Xcode\s+app\s+bundle/i,
|
|
296
|
+
/macios-missing-xcode/i
|
|
297
|
+
].some((re) => re.test(output));
|
|
275
298
|
var checkDotnetSdk = () => {
|
|
276
299
|
const res = run(DOTNET, ["--list-sdks"]);
|
|
277
300
|
if (!res.found) {
|
|
@@ -363,17 +386,17 @@ var collectRequirements = (opts = {}) => {
|
|
|
363
386
|
};
|
|
364
387
|
var printRequirements = (reqs) => {
|
|
365
388
|
for (const r of reqs) {
|
|
366
|
-
const icon = r.status === "ok" ?
|
|
367
|
-
const detail = r.detail ? ` ${
|
|
389
|
+
const icon = r.status === "ok" ? chalk4.green("\u2713") : r.status === "missing" ? chalk4.red("\u2717") : chalk4.yellow("?");
|
|
390
|
+
const detail = r.detail ? ` ${chalk4.dim(`(${r.detail})`)}` : "";
|
|
368
391
|
console.log(` ${icon} ${r.name}${detail}`);
|
|
369
392
|
if (r.status === "missing" && r.fix) {
|
|
370
|
-
console.log(` ${
|
|
393
|
+
console.log(` ${chalk4.dim("fix:")} ${chalk4.cyan(r.fix)}`);
|
|
371
394
|
}
|
|
372
395
|
}
|
|
373
396
|
};
|
|
374
397
|
var runDoctor = async () => {
|
|
375
398
|
console.log();
|
|
376
|
-
console.log(` ${
|
|
399
|
+
console.log(` ${chalk4.bold.cyan("vidra doctor")}`);
|
|
377
400
|
console.log();
|
|
378
401
|
const reqs = collectRequirements();
|
|
379
402
|
printRequirements(reqs);
|
|
@@ -381,7 +404,7 @@ var runDoctor = async () => {
|
|
|
381
404
|
const missing = reqs.filter((r) => r.status === "missing");
|
|
382
405
|
if (missing.length === 0) {
|
|
383
406
|
console.log(
|
|
384
|
-
` ${
|
|
407
|
+
` ${chalk4.green("All checks passed.")} You're ready to run ${chalk4.cyan(
|
|
385
408
|
"vidra dev"
|
|
386
409
|
)}.`
|
|
387
410
|
);
|
|
@@ -389,9 +412,9 @@ var runDoctor = async () => {
|
|
|
389
412
|
return 0;
|
|
390
413
|
}
|
|
391
414
|
console.log(
|
|
392
|
-
` ${
|
|
415
|
+
` ${chalk4.yellow(
|
|
393
416
|
`${missing.length} issue(s) found.`
|
|
394
|
-
)} Apply the fixes above, then re-run ${
|
|
417
|
+
)} Apply the fixes above, then re-run ${chalk4.cyan("vidra doctor")}.`
|
|
395
418
|
);
|
|
396
419
|
console.log();
|
|
397
420
|
return 1;
|
|
@@ -399,9 +422,9 @@ var runDoctor = async () => {
|
|
|
399
422
|
var installWorkload = (csprojPath) => {
|
|
400
423
|
const args = csprojPath ? ["workload", "restore", csprojPath] : ["workload", "install", "maui"];
|
|
401
424
|
console.log();
|
|
402
|
-
console.log(` ${
|
|
425
|
+
console.log(` ${chalk4.dim(`Running: ${DOTNET} ${args.join(" ")}`)}`);
|
|
403
426
|
console.log(
|
|
404
|
-
` ${
|
|
427
|
+
` ${chalk4.dim(
|
|
405
428
|
"This can download several hundred MB and take a few minutes."
|
|
406
429
|
)}`
|
|
407
430
|
);
|
|
@@ -411,13 +434,13 @@ var installWorkload = (csprojPath) => {
|
|
|
411
434
|
return true;
|
|
412
435
|
} catch {
|
|
413
436
|
console.error();
|
|
414
|
-
console.error(` ${
|
|
437
|
+
console.error(` ${chalk4.red("Workload install failed.")}`);
|
|
415
438
|
console.error(
|
|
416
|
-
` ${
|
|
439
|
+
` ${chalk4.dim(
|
|
417
440
|
"If this is a permissions error, your SDK is in a system location and needs elevation:"
|
|
418
441
|
)}`
|
|
419
442
|
);
|
|
420
|
-
console.error(` ${
|
|
443
|
+
console.error(` ${chalk4.cyan("sudo dotnet workload install maui")}`);
|
|
421
444
|
console.error();
|
|
422
445
|
return false;
|
|
423
446
|
}
|
|
@@ -426,9 +449,9 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
426
449
|
const dotnet = checkDotnetSdk();
|
|
427
450
|
if (dotnet.status === "missing") {
|
|
428
451
|
console.log();
|
|
429
|
-
console.log(` ${
|
|
452
|
+
console.log(` ${chalk4.yellow("!")} ${dotnet.name} \u2014 ${dotnet.detail}`);
|
|
430
453
|
if (dotnet.fix) {
|
|
431
|
-
console.log(` ${
|
|
454
|
+
console.log(` ${chalk4.dim("fix:")} ${chalk4.cyan(dotnet.fix)}`);
|
|
432
455
|
}
|
|
433
456
|
return false;
|
|
434
457
|
}
|
|
@@ -436,7 +459,7 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
436
459
|
if (isMauiWorkloadInstalled()) return true;
|
|
437
460
|
console.log();
|
|
438
461
|
console.log(
|
|
439
|
-
` ${
|
|
462
|
+
` ${chalk4.yellow("!")} The .NET MAUI workload is required but not installed.`
|
|
440
463
|
);
|
|
441
464
|
const interactive = opts.interactive ?? isInteractive();
|
|
442
465
|
if (interactive) {
|
|
@@ -454,31 +477,50 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
454
477
|
}
|
|
455
478
|
if (install) {
|
|
456
479
|
if (installWorkload(opts.csprojPath) && isMauiWorkloadInstalled()) {
|
|
457
|
-
console.log(` ${
|
|
480
|
+
console.log(` ${chalk4.green("\u2713")} MAUI workload installed.`);
|
|
458
481
|
return true;
|
|
459
482
|
}
|
|
460
483
|
return false;
|
|
461
484
|
}
|
|
462
485
|
}
|
|
463
486
|
console.log(
|
|
464
|
-
` ${
|
|
487
|
+
` ${chalk4.dim("run:")} ${chalk4.cyan("dotnet workload install maui")}`
|
|
465
488
|
);
|
|
466
|
-
console.log(` ${
|
|
489
|
+
console.log(` ${chalk4.dim("docs:")} ${chalk4.cyan(MAUI_DOCS)}`);
|
|
467
490
|
return false;
|
|
468
491
|
};
|
|
469
492
|
var printWorkloadHint = () => {
|
|
470
493
|
console.error();
|
|
471
494
|
console.error(
|
|
472
|
-
` ${
|
|
495
|
+
` ${chalk4.yellow("This looks like a missing .NET MAUI workload.")}`
|
|
473
496
|
);
|
|
474
497
|
console.error(
|
|
475
|
-
` ${
|
|
498
|
+
` ${chalk4.dim("fix: ")} ${chalk4.cyan("dotnet workload install maui")}`
|
|
476
499
|
);
|
|
477
500
|
console.error(
|
|
478
|
-
` ${
|
|
501
|
+
` ${chalk4.dim("check:")} ${chalk4.cyan("vidra doctor")}`
|
|
479
502
|
);
|
|
480
503
|
console.error();
|
|
481
504
|
};
|
|
505
|
+
var printXcodeHint = () => {
|
|
506
|
+
console.error();
|
|
507
|
+
console.error(
|
|
508
|
+
` ${chalk4.yellow(
|
|
509
|
+
"Mac Catalyst builds need the full Xcode app, not just the Command Line Tools."
|
|
510
|
+
)}`
|
|
511
|
+
);
|
|
512
|
+
console.error(` ${chalk4.dim("1.")} Install Xcode from the App Store`);
|
|
513
|
+
console.error(
|
|
514
|
+
` ${chalk4.dim("2.")} ${chalk4.cyan(
|
|
515
|
+
"sudo xcode-select -s /Applications/Xcode.app/Contents/Developer"
|
|
516
|
+
)}`
|
|
517
|
+
);
|
|
518
|
+
console.error(
|
|
519
|
+
` ${chalk4.dim("3.")} ${chalk4.cyan("sudo xcodebuild -runFirstLaunch")}`
|
|
520
|
+
);
|
|
521
|
+
console.error(` ${chalk4.dim("check:")} ${chalk4.cyan("vidra doctor")}`);
|
|
522
|
+
console.error();
|
|
523
|
+
};
|
|
482
524
|
|
|
483
525
|
// src/commands/build.ts
|
|
484
526
|
var VERSION = "0.1.0";
|
|
@@ -492,22 +534,22 @@ var buildCommand = async (argv) => {
|
|
|
492
534
|
const targetName = args["target"] || detectPlatform();
|
|
493
535
|
console.log();
|
|
494
536
|
console.log(
|
|
495
|
-
` ${
|
|
537
|
+
` ${chalk5.bold.cyan("vidra build")} ${chalk5.dim(`v${VERSION}`)}`
|
|
496
538
|
);
|
|
497
539
|
console.log();
|
|
498
540
|
const target = TARGETS[targetName];
|
|
499
541
|
if (!target) {
|
|
500
542
|
const supported = Object.keys(TARGETS).join(", ");
|
|
501
543
|
console.error(
|
|
502
|
-
|
|
544
|
+
chalk5.red(
|
|
503
545
|
` Unsupported target: ${targetName}. Supported: ${supported}`
|
|
504
546
|
)
|
|
505
547
|
);
|
|
506
548
|
process.exit(1);
|
|
507
549
|
}
|
|
508
550
|
const project = detectProject(process.cwd());
|
|
509
|
-
console.log(` ${
|
|
510
|
-
console.log(` ${
|
|
551
|
+
console.log(` ${chalk5.dim("Project:")} ${chalk5.cyan(project.projectName)}`);
|
|
552
|
+
console.log(` ${chalk5.dim("Target:")} ${chalk5.cyan(target.name)} (${target.framework})`);
|
|
511
553
|
console.log();
|
|
512
554
|
if (!await ensureMauiWorkload({ csprojPath: project.csprojPath })) {
|
|
513
555
|
process.exit(1);
|
|
@@ -518,12 +560,12 @@ var buildCommand = async (argv) => {
|
|
|
518
560
|
const bundlePath = target.findBundle(publishDir, project.projectName);
|
|
519
561
|
if (!bundlePath) {
|
|
520
562
|
console.error(
|
|
521
|
-
|
|
563
|
+
chalk5.red(` Could not find build artifact in ${publishDir}`)
|
|
522
564
|
);
|
|
523
565
|
process.exit(1);
|
|
524
566
|
}
|
|
525
567
|
console.log(
|
|
526
|
-
` ${
|
|
568
|
+
` ${chalk5.dim("Bundle:")} ${chalk5.cyan(path5.basename(bundlePath))}`
|
|
527
569
|
);
|
|
528
570
|
if (target.name === "macos") {
|
|
529
571
|
signMacAppBundleIfPossible(bundlePath, {
|
|
@@ -535,7 +577,7 @@ var buildCommand = async (argv) => {
|
|
|
535
577
|
const outputDir = path5.join(project.root, "dist");
|
|
536
578
|
fs4.ensureDirSync(outputDir);
|
|
537
579
|
console.log();
|
|
538
|
-
console.log(` ${
|
|
580
|
+
console.log(` ${chalk5.dim(`Packaging for ${target.name}...`)}`);
|
|
539
581
|
const startPkg = Date.now();
|
|
540
582
|
let outputPath;
|
|
541
583
|
try {
|
|
@@ -544,46 +586,44 @@ var buildCommand = async (argv) => {
|
|
|
544
586
|
displayVersion: project.displayVersion
|
|
545
587
|
});
|
|
546
588
|
} catch (e) {
|
|
547
|
-
|
|
548
|
-
console.error(
|
|
549
|
-
console.error(chalk4.dim(err.stderr?.toString() || err.message));
|
|
589
|
+
console.error(chalk5.red(` Packaging failed.`));
|
|
590
|
+
console.error(chalk5.dim(formatProcessError(e)));
|
|
550
591
|
process.exit(1);
|
|
551
592
|
}
|
|
552
593
|
const pkgTime = ((Date.now() - startPkg) / 1e3).toFixed(1);
|
|
553
594
|
const sizeBytes = fs4.statSync(outputPath).size;
|
|
554
595
|
const sizeMB = (sizeBytes / (1024 * 1024)).toFixed(1);
|
|
555
596
|
console.log(
|
|
556
|
-
` ${
|
|
597
|
+
` ${chalk5.green(">")} ${path5.basename(outputPath)} ${chalk5.dim(`(${sizeMB} MB, ${pkgTime}s)`)}`
|
|
557
598
|
);
|
|
558
599
|
console.log();
|
|
559
600
|
console.log(
|
|
560
|
-
` ${
|
|
601
|
+
` ${chalk5.green("Done!")} Output: ${chalk5.cyan(path5.relative(project.root, outputPath))}`
|
|
561
602
|
);
|
|
562
603
|
console.log();
|
|
563
604
|
};
|
|
564
605
|
var stepBuildUi = (project, verbose) => {
|
|
565
|
-
console.log(` ${
|
|
606
|
+
console.log(` ${chalk5.dim("Building UI...")}`);
|
|
566
607
|
const start = Date.now();
|
|
567
608
|
try {
|
|
568
|
-
|
|
609
|
+
execSync3("npm run build", {
|
|
569
610
|
cwd: project.uiDir,
|
|
570
611
|
stdio: verbose ? "inherit" : "pipe"
|
|
571
612
|
});
|
|
572
613
|
} catch (e) {
|
|
573
|
-
|
|
574
|
-
console.error(
|
|
575
|
-
console.error(chalk4.dim(err.stderr?.toString() || err.message));
|
|
614
|
+
console.error(chalk5.red(" Vite build failed."));
|
|
615
|
+
console.error(chalk5.dim(formatBuildError(e)));
|
|
576
616
|
process.exit(1);
|
|
577
617
|
}
|
|
578
618
|
const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
|
|
579
|
-
console.log(` ${
|
|
619
|
+
console.log(` ${chalk5.green(">")} Vite build complete ${chalk5.dim(`(${elapsed}s)`)}`);
|
|
580
620
|
console.log();
|
|
581
621
|
};
|
|
582
622
|
var stepCopyAssets = (project) => {
|
|
583
|
-
console.log(` ${
|
|
623
|
+
console.log(` ${chalk5.dim("Copying assets to host project...")}`);
|
|
584
624
|
const viteDist = path5.join(project.uiDir, "dist");
|
|
585
625
|
if (!fs4.existsSync(viteDist)) {
|
|
586
|
-
console.error(
|
|
626
|
+
console.error(chalk5.red(` ui/dist not found. Vite build may have failed.`));
|
|
587
627
|
process.exit(1);
|
|
588
628
|
}
|
|
589
629
|
const wwwroot = path5.join(project.hostDir, "Resources", "Raw", "wwwroot");
|
|
@@ -591,7 +631,7 @@ var stepCopyAssets = (project) => {
|
|
|
591
631
|
fs4.copySync(viteDist, wwwroot);
|
|
592
632
|
const fileCount = countFiles(wwwroot);
|
|
593
633
|
console.log(
|
|
594
|
-
` ${
|
|
634
|
+
` ${chalk5.green(">")} ${fileCount} files -> ${chalk5.dim("Resources/Raw/wwwroot/")}`
|
|
595
635
|
);
|
|
596
636
|
console.log();
|
|
597
637
|
};
|
|
@@ -608,12 +648,12 @@ var countFiles = (dir) => {
|
|
|
608
648
|
};
|
|
609
649
|
var stepDotnetPublish = (project, target, verbose) => {
|
|
610
650
|
console.log(
|
|
611
|
-
` ${
|
|
651
|
+
` ${chalk5.dim(`Publishing .NET host (${target.framework})...`)}`
|
|
612
652
|
);
|
|
613
653
|
const start = Date.now();
|
|
614
654
|
const extraArgs = target.extraPublishArgs ?? "-p:CreatePackage=false";
|
|
615
655
|
try {
|
|
616
|
-
|
|
656
|
+
execSync3(
|
|
617
657
|
`dotnet publish "${project.csprojPath}" -c Release -f ${target.framework} ${extraArgs}`,
|
|
618
658
|
{
|
|
619
659
|
cwd: project.root,
|
|
@@ -621,16 +661,21 @@ var stepDotnetPublish = (project, target, verbose) => {
|
|
|
621
661
|
}
|
|
622
662
|
);
|
|
623
663
|
} catch (e) {
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
console.error(
|
|
627
|
-
console.error(chalk4.dim(output));
|
|
664
|
+
const output = formatBuildError(e);
|
|
665
|
+
console.error(chalk5.red(" dotnet publish failed."));
|
|
666
|
+
console.error(chalk5.dim(output));
|
|
628
667
|
if (looksLikeMissingWorkload(output)) printWorkloadHint();
|
|
668
|
+
else if (looksLikeMissingXcode(output)) printXcodeHint();
|
|
669
|
+
if (!verbose) {
|
|
670
|
+
console.error(
|
|
671
|
+
chalk5.dim(" Re-run with --verbose for the full build log.")
|
|
672
|
+
);
|
|
673
|
+
}
|
|
629
674
|
process.exit(1);
|
|
630
675
|
}
|
|
631
676
|
const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
|
|
632
677
|
console.log(
|
|
633
|
-
` ${
|
|
678
|
+
` ${chalk5.green(">")} dotnet publish complete ${chalk5.dim(`(${elapsed}s)`)}`
|
|
634
679
|
);
|
|
635
680
|
const publishDir = path5.join(
|
|
636
681
|
project.hostDir,
|
|
@@ -646,7 +691,7 @@ import path6 from "path";
|
|
|
646
691
|
import fs5 from "fs-extra";
|
|
647
692
|
import { execFileSync as execFileSync3, spawn } from "child_process";
|
|
648
693
|
import { request } from "http";
|
|
649
|
-
import
|
|
694
|
+
import chalk6 from "chalk";
|
|
650
695
|
var VERSION2 = "0.1.0";
|
|
651
696
|
var POLL_INTERVAL_MS = 500;
|
|
652
697
|
var POLL_TIMEOUT_MS = 3e4;
|
|
@@ -662,7 +707,9 @@ var TARGETS2 = {
|
|
|
662
707
|
framework: "net10.0-windows10.0.19041.0"
|
|
663
708
|
}
|
|
664
709
|
};
|
|
665
|
-
var devCommand =
|
|
710
|
+
var devCommand = (argv) => startSession(argv, { vite: true });
|
|
711
|
+
var runCommand = (argv) => startSession(argv, { vite: false });
|
|
712
|
+
var startSession = async (argv, opts) => {
|
|
666
713
|
const args = parseArgs(["_", "_", ...argv]);
|
|
667
714
|
const targetName = args["target"] || detectPlatform();
|
|
668
715
|
const verbose = !!args["verbose"];
|
|
@@ -671,7 +718,7 @@ var devCommand = async (argv) => {
|
|
|
671
718
|
if (!target) {
|
|
672
719
|
const supported = Object.keys(TARGETS2).join(", ");
|
|
673
720
|
console.error(
|
|
674
|
-
|
|
721
|
+
chalk6.red(
|
|
675
722
|
` Unsupported target: ${targetName}. Supported: ${supported}`
|
|
676
723
|
)
|
|
677
724
|
);
|
|
@@ -682,15 +729,16 @@ var devCommand = async (argv) => {
|
|
|
682
729
|
if (!await ensureMauiWorkload({ csprojPath: project.csprojPath })) {
|
|
683
730
|
process.exit(1);
|
|
684
731
|
}
|
|
685
|
-
const session = new DevSession(project, target, viteUrl, verbose);
|
|
732
|
+
const session = new DevSession(project, target, viteUrl, verbose, opts);
|
|
686
733
|
await session.run();
|
|
687
734
|
};
|
|
688
735
|
var DevSession = class {
|
|
689
|
-
constructor(project, target, viteUrl, verbose) {
|
|
736
|
+
constructor(project, target, viteUrl, verbose, options = {}) {
|
|
690
737
|
this.project = project;
|
|
691
738
|
this.target = target;
|
|
692
739
|
this.viteUrl = viteUrl;
|
|
693
740
|
this.verbose = verbose;
|
|
741
|
+
this.vite = options.vite ?? true;
|
|
694
742
|
}
|
|
695
743
|
project;
|
|
696
744
|
target;
|
|
@@ -698,32 +746,39 @@ var DevSession = class {
|
|
|
698
746
|
verbose;
|
|
699
747
|
children = [];
|
|
700
748
|
buildConfig = process.env.VIDRA_BUILD_CONFIG || "Debug";
|
|
749
|
+
vite;
|
|
701
750
|
shuttingDown = false;
|
|
702
751
|
async run() {
|
|
703
752
|
this.installSignalHandlers();
|
|
704
753
|
console.log();
|
|
705
|
-
console.log(
|
|
754
|
+
console.log(
|
|
755
|
+
` ${chalk6.bold.cyan(this.vite ? "vidra dev" : "vidra run")} ${chalk6.dim(`v${VERSION2}`)}`
|
|
756
|
+
);
|
|
706
757
|
console.log();
|
|
707
|
-
console.log(` ${
|
|
758
|
+
console.log(` ${chalk6.dim("Project:")} ${chalk6.cyan(this.project.projectName)}`);
|
|
708
759
|
console.log(
|
|
709
|
-
` ${
|
|
760
|
+
` ${chalk6.dim("Target:")} ${chalk6.cyan(this.target.name)} (${this.target.framework})`
|
|
710
761
|
);
|
|
711
762
|
console.log();
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
)
|
|
763
|
+
let vite;
|
|
764
|
+
if (this.vite) {
|
|
765
|
+
vite = this.startVite();
|
|
766
|
+
try {
|
|
767
|
+
await waitForServer(this.viteUrl, POLL_TIMEOUT_MS);
|
|
768
|
+
} catch (error) {
|
|
769
|
+
console.error(chalk6.red(` ${error.message}`));
|
|
770
|
+
this.shutdown(1);
|
|
771
|
+
}
|
|
772
|
+
console.log(` ${chalk6.dim("Vite:")} ${chalk6.cyan(this.viteUrl)}`);
|
|
773
|
+
console.log();
|
|
774
|
+
} else {
|
|
775
|
+
console.log(
|
|
776
|
+
` ${chalk6.dim("UI:")} ${chalk6.cyan(this.viteUrl)} ${chalk6.dim("(start it separately, e.g. `npm run dev:ui`)")}`
|
|
720
777
|
);
|
|
721
|
-
|
|
778
|
+
console.log();
|
|
722
779
|
}
|
|
723
|
-
console.log(` ${chalk5.dim("Vite:")} ${chalk5.cyan(this.viteUrl)}`);
|
|
724
|
-
console.log();
|
|
725
780
|
const host = this.target.name === "macos" ? this.launchMacosHost() : this.launchWindowsHost();
|
|
726
|
-
await waitForExit(vite, host);
|
|
781
|
+
await waitForExit(...vite ? [vite, host] : [host]);
|
|
727
782
|
}
|
|
728
783
|
installSignalHandlers() {
|
|
729
784
|
process.on("SIGINT", () => {
|
|
@@ -735,7 +790,7 @@ var DevSession = class {
|
|
|
735
790
|
});
|
|
736
791
|
}
|
|
737
792
|
startVite() {
|
|
738
|
-
console.log(` ${
|
|
793
|
+
console.log(` ${chalk6.dim("Starting Vite dev server...")}`);
|
|
739
794
|
const vite = spawn(NPM_COMMAND, ["run", "dev"], {
|
|
740
795
|
cwd: this.project.uiDir,
|
|
741
796
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -744,7 +799,7 @@ var DevSession = class {
|
|
|
744
799
|
}
|
|
745
800
|
launchMacosHost() {
|
|
746
801
|
console.log(
|
|
747
|
-
` ${
|
|
802
|
+
` ${chalk6.dim(`Building MAUI host (${this.target.framework})...`)}`
|
|
748
803
|
);
|
|
749
804
|
try {
|
|
750
805
|
execFileSync3(
|
|
@@ -763,10 +818,16 @@ var DevSession = class {
|
|
|
763
818
|
}
|
|
764
819
|
);
|
|
765
820
|
} catch (error) {
|
|
766
|
-
const output =
|
|
767
|
-
console.error(
|
|
768
|
-
console.error(
|
|
821
|
+
const output = formatBuildError(error);
|
|
822
|
+
console.error(chalk6.red(" MAUI build failed."));
|
|
823
|
+
console.error(chalk6.dim(output));
|
|
769
824
|
if (looksLikeMissingWorkload(output)) printWorkloadHint();
|
|
825
|
+
else if (looksLikeMissingXcode(output)) printXcodeHint();
|
|
826
|
+
if (!this.verbose) {
|
|
827
|
+
console.error(
|
|
828
|
+
chalk6.dim(" Re-run with --verbose for the full build log.")
|
|
829
|
+
);
|
|
830
|
+
}
|
|
770
831
|
process.exit(1);
|
|
771
832
|
}
|
|
772
833
|
const appBundle = findMacAppBundle(
|
|
@@ -776,7 +837,7 @@ var DevSession = class {
|
|
|
776
837
|
);
|
|
777
838
|
if (!appBundle) {
|
|
778
839
|
console.error(
|
|
779
|
-
|
|
840
|
+
chalk6.red(
|
|
780
841
|
` Could not find .app bundle in ${path6.join(this.project.hostDir, "bin", this.buildConfig, this.target.framework)}`
|
|
781
842
|
)
|
|
782
843
|
);
|
|
@@ -790,11 +851,11 @@ var DevSession = class {
|
|
|
790
851
|
const binary = findMacExecutable(appBundle);
|
|
791
852
|
if (!binary) {
|
|
792
853
|
console.error(
|
|
793
|
-
|
|
854
|
+
chalk6.red(` Could not find the app executable in ${appBundle}.`)
|
|
794
855
|
);
|
|
795
856
|
process.exit(1);
|
|
796
857
|
}
|
|
797
|
-
console.log(` ${
|
|
858
|
+
console.log(` ${chalk6.dim("Launching host...")}`);
|
|
798
859
|
const host = spawn(binary, [], {
|
|
799
860
|
cwd: this.project.root,
|
|
800
861
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -803,7 +864,7 @@ var DevSession = class {
|
|
|
803
864
|
return this.registerChild(host, "host", path6.basename(binary));
|
|
804
865
|
}
|
|
805
866
|
launchWindowsHost() {
|
|
806
|
-
console.log(` ${
|
|
867
|
+
console.log(` ${chalk6.dim("Launching host...")}`);
|
|
807
868
|
const host = spawn(
|
|
808
869
|
DOTNET_COMMAND,
|
|
809
870
|
[
|
|
@@ -827,27 +888,38 @@ var DevSession = class {
|
|
|
827
888
|
this.children.push(child);
|
|
828
889
|
prefixStream(child.stdout, tag);
|
|
829
890
|
prefixStream(child.stderr, tag);
|
|
830
|
-
child.on("exit", (code) => {
|
|
891
|
+
child.on("exit", (code, signal) => {
|
|
831
892
|
if (this.shuttingDown) return;
|
|
832
893
|
if (tag === "ui") {
|
|
833
894
|
const exitCode = code ?? 1;
|
|
834
895
|
console.error(
|
|
835
|
-
|
|
896
|
+
chalk6.red(`
|
|
836
897
|
${label} exited with code ${exitCode}.`)
|
|
837
898
|
);
|
|
838
899
|
this.shutdown(exitCode);
|
|
839
900
|
return;
|
|
840
901
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
902
|
+
const failed = code !== null && code !== 0 || signal !== null;
|
|
903
|
+
if (failed) {
|
|
904
|
+
console.error(
|
|
905
|
+
chalk6.red(
|
|
906
|
+
`
|
|
907
|
+
${label} exited with ${signal ? `signal ${signal}` : `code ${code}`}.`
|
|
908
|
+
)
|
|
909
|
+
);
|
|
910
|
+
if (tag === "host" && this.target.name === "macos") {
|
|
911
|
+
printMacLaunchHint();
|
|
912
|
+
}
|
|
844
913
|
}
|
|
845
|
-
this.shutdown(code ?? 0);
|
|
914
|
+
this.shutdown(code ?? (signal ? 1 : 0));
|
|
846
915
|
});
|
|
847
916
|
child.on("error", (error) => {
|
|
848
917
|
if (this.shuttingDown) return;
|
|
849
|
-
console.error(
|
|
918
|
+
console.error(chalk6.red(`
|
|
850
919
|
Failed to start ${label}: ${error.message}`));
|
|
920
|
+
if (tag === "host" && this.target.name === "macos") {
|
|
921
|
+
printMacLaunchHint();
|
|
922
|
+
}
|
|
851
923
|
this.shutdown(1);
|
|
852
924
|
});
|
|
853
925
|
return child;
|
|
@@ -863,12 +935,12 @@ var DevSession = class {
|
|
|
863
935
|
};
|
|
864
936
|
var ensureTargetMatchesHostOs = (targetName) => {
|
|
865
937
|
if (targetName === "macos" && process.platform !== "darwin") {
|
|
866
|
-
console.error(
|
|
938
|
+
console.error(chalk6.red(" The macOS dev target can only run on macOS."));
|
|
867
939
|
process.exit(1);
|
|
868
940
|
}
|
|
869
941
|
if (targetName === "windows" && process.platform !== "win32") {
|
|
870
942
|
console.error(
|
|
871
|
-
|
|
943
|
+
chalk6.red(" The Windows dev target can only run on Windows.")
|
|
872
944
|
);
|
|
873
945
|
process.exit(1);
|
|
874
946
|
}
|
|
@@ -916,11 +988,12 @@ var waitForServer = (url, timeoutMs) => {
|
|
|
916
988
|
poll();
|
|
917
989
|
});
|
|
918
990
|
};
|
|
919
|
-
var waitForExit = (
|
|
991
|
+
var waitForExit = (...children) => {
|
|
920
992
|
return new Promise((resolve) => {
|
|
921
993
|
const resolveOnce = () => resolve();
|
|
922
|
-
|
|
923
|
-
|
|
994
|
+
for (const child of children) {
|
|
995
|
+
child.once("exit", resolveOnce);
|
|
996
|
+
}
|
|
924
997
|
});
|
|
925
998
|
};
|
|
926
999
|
var findMacAppBundle = (hostDir, framework, buildConfig) => {
|
|
@@ -965,39 +1038,50 @@ var killChild = (child) => {
|
|
|
965
1038
|
}
|
|
966
1039
|
child.kill("SIGTERM");
|
|
967
1040
|
};
|
|
968
|
-
var
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1041
|
+
var printMacLaunchHint = () => {
|
|
1042
|
+
console.error();
|
|
1043
|
+
console.error(chalk6.yellow(" The host built but the app couldn't launch."));
|
|
1044
|
+
console.error(
|
|
1045
|
+
chalk6.dim(
|
|
1046
|
+
" On macOS this is usually code signing / Gatekeeper for a locally built app:"
|
|
1047
|
+
)
|
|
1048
|
+
);
|
|
1049
|
+
console.error(
|
|
1050
|
+
` ${chalk6.dim("\u2022")} Install full Xcode, then run ${chalk6.cyan("vidra doctor")} to verify`
|
|
1051
|
+
);
|
|
1052
|
+
console.error(
|
|
1053
|
+
` ${chalk6.dim("\u2022")} Approve it once in Finder: right-click the ${chalk6.cyan(".app")} and choose ${chalk6.cyan("Open")}`
|
|
1054
|
+
);
|
|
1055
|
+
console.error(
|
|
1056
|
+
` ${chalk6.dim("\u2022")} Or provide a signing identity via ${chalk6.cyan("VIDRA_MACOS_CODESIGN_KEY")}`
|
|
1057
|
+
);
|
|
1058
|
+
console.error();
|
|
977
1059
|
};
|
|
978
1060
|
|
|
979
1061
|
// src/cli.ts
|
|
980
|
-
var VERSION3 = "0.1.
|
|
1062
|
+
var VERSION3 = "0.1.5";
|
|
981
1063
|
var printHelp = () => {
|
|
982
1064
|
console.log(`
|
|
983
|
-
${
|
|
1065
|
+
${chalk7.bold("vidra")} ${chalk7.dim(`v${VERSION3}`)}
|
|
984
1066
|
|
|
985
|
-
${
|
|
1067
|
+
${chalk7.dim("Usage:")}
|
|
986
1068
|
vidra <command> [options]
|
|
987
1069
|
|
|
988
|
-
${
|
|
989
|
-
dev Start the development environment
|
|
1070
|
+
${chalk7.dim("Commands:")}
|
|
1071
|
+
dev Start the development environment (Vite + native host)
|
|
1072
|
+
run Build and launch the native host only (no Vite dev server)
|
|
990
1073
|
build Build and package the application for distribution
|
|
991
1074
|
doctor Check that your environment is set up to build Vidra apps
|
|
992
1075
|
help Show this help message
|
|
993
1076
|
|
|
994
|
-
${
|
|
995
|
-
vidra dev ${
|
|
996
|
-
vidra dev --target windows ${
|
|
997
|
-
vidra
|
|
998
|
-
vidra build
|
|
999
|
-
vidra build --
|
|
1000
|
-
vidra
|
|
1077
|
+
${chalk7.dim("Examples:")}
|
|
1078
|
+
vidra dev ${chalk7.dim("# start Vite + native host")}
|
|
1079
|
+
vidra dev --target windows ${chalk7.dim("# run the Windows host")}
|
|
1080
|
+
vidra run ${chalk7.dim("# launch the host (UI served separately)")}
|
|
1081
|
+
vidra build ${chalk7.dim("# auto-detect platform")}
|
|
1082
|
+
vidra build --target macos ${chalk7.dim("# macOS DMG")}
|
|
1083
|
+
vidra build --verbose ${chalk7.dim("# show full build output")}
|
|
1084
|
+
vidra doctor ${chalk7.dim("# verify .NET SDK + MAUI workload")}
|
|
1001
1085
|
`);
|
|
1002
1086
|
};
|
|
1003
1087
|
var main = async () => {
|
|
@@ -1007,6 +1091,9 @@ var main = async () => {
|
|
|
1007
1091
|
case "dev":
|
|
1008
1092
|
await devCommand(args.slice(1));
|
|
1009
1093
|
break;
|
|
1094
|
+
case "run":
|
|
1095
|
+
await runCommand(args.slice(1));
|
|
1096
|
+
break;
|
|
1010
1097
|
case "build":
|
|
1011
1098
|
await buildCommand(args.slice(1));
|
|
1012
1099
|
break;
|
|
@@ -1024,13 +1111,13 @@ var main = async () => {
|
|
|
1024
1111
|
console.log(VERSION3);
|
|
1025
1112
|
break;
|
|
1026
1113
|
default:
|
|
1027
|
-
console.error(
|
|
1114
|
+
console.error(chalk7.red(` Unknown command: ${command}
|
|
1028
1115
|
`));
|
|
1029
1116
|
printHelp();
|
|
1030
1117
|
process.exit(1);
|
|
1031
1118
|
}
|
|
1032
1119
|
};
|
|
1033
1120
|
main().catch((e) => {
|
|
1034
|
-
console.error(
|
|
1121
|
+
console.error(chalk7.red(e.message));
|
|
1035
1122
|
process.exit(1);
|
|
1036
1123
|
});
|
package/dist/index.js
CHANGED
|
@@ -37,13 +37,21 @@ var parseArgs = (argv) => {
|
|
|
37
37
|
// src/exec.ts
|
|
38
38
|
import { execSync } from "child_process";
|
|
39
39
|
import chalk from "chalk";
|
|
40
|
+
var toText = (value) => {
|
|
41
|
+
if (value == null) return "";
|
|
42
|
+
return Buffer.isBuffer(value) ? value.toString() : value;
|
|
43
|
+
};
|
|
44
|
+
var formatProcessError = (error) => {
|
|
45
|
+
const err = error;
|
|
46
|
+
const combined = [toText(err.stderr), toText(err.stdout)].map((s) => s.trim()).filter((s) => s.length > 0).join("\n").trim();
|
|
47
|
+
return combined.length > 0 ? combined : err.message ?? String(error);
|
|
48
|
+
};
|
|
40
49
|
var exec = (cmd, cwd) => {
|
|
41
50
|
try {
|
|
42
51
|
execSync(cmd, { cwd, stdio: "pipe" });
|
|
43
52
|
} catch (e) {
|
|
44
|
-
const err = e;
|
|
45
53
|
console.error(chalk.red(` Command failed: ${cmd}`));
|
|
46
|
-
console.error(chalk.dim(
|
|
54
|
+
console.error(chalk.dim(formatProcessError(e)));
|
|
47
55
|
process.exit(1);
|
|
48
56
|
}
|
|
49
57
|
};
|
package/package.json
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"build": "vidra build",
|
|
6
6
|
"dev": "vidra dev",
|
|
7
7
|
"dev:ui": "npm run dev --prefix ui",
|
|
8
|
-
"dev:host:macos": "
|
|
9
|
-
"dev:host:windows": "
|
|
8
|
+
"dev:host:macos": "vidra run --target macos",
|
|
9
|
+
"dev:host:windows": "vidra run --target windows"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"create-vidra-app": "{{cliVersion}}"
|