create-vidra-app 0.3.0 → 0.4.0
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 +3265 -843
- package/dist/index.js +61 -21
- package/package.json +1 -1
- package/templates/react-vite/README.md +16 -9
- package/templates/react-vite/_gitignore +4 -0
- package/templates/react-vite/package.json +1 -0
- package/templates/react-vite/src/{{projectName}}.Host/Entitlements.plist +18 -0
- package/templates/react-vite/src/{{projectName}}.Host/MauiProgram.cs +19 -0
- package/templates/react-vite/src/{{projectName}}.Host/Platforms/MacCatalyst/Program.cs +24 -0
- package/templates/react-vite/src/{{projectName}}.Host/Platforms/Windows/Program.cs +45 -0
- package/templates/react-vite/src/{{projectName}}.Host/{{projectName}}.Host.csproj +37 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import prompts2 from "prompts";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import fs9 from "fs-extra";
|
|
4
|
+
import path10 from "path";
|
|
5
5
|
import { randomUUID } from "crypto";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
@@ -170,15 +170,53 @@ var applyReplacements = (str, replacements) => {
|
|
|
170
170
|
};
|
|
171
171
|
|
|
172
172
|
// src/doctor.ts
|
|
173
|
-
import { execFileSync } from "child_process";
|
|
173
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
174
|
+
import fs8 from "fs";
|
|
175
|
+
import path9 from "path";
|
|
174
176
|
import prompts from "prompts";
|
|
177
|
+
|
|
178
|
+
// src/signing.ts
|
|
179
|
+
import path2 from "path";
|
|
180
|
+
import fs2 from "fs-extra";
|
|
181
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
182
|
+
|
|
183
|
+
// src/notarize.ts
|
|
184
|
+
import path3 from "path";
|
|
185
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
186
|
+
|
|
187
|
+
// src/windows-signing.ts
|
|
188
|
+
import path4 from "path";
|
|
189
|
+
import fs3 from "fs-extra";
|
|
190
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
191
|
+
|
|
192
|
+
// src/velopack.ts
|
|
193
|
+
import path5 from "path";
|
|
194
|
+
import os from "os";
|
|
195
|
+
import fs4 from "fs-extra";
|
|
196
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
197
|
+
|
|
198
|
+
// src/update-config.ts
|
|
199
|
+
import path6 from "path";
|
|
200
|
+
import fs5 from "fs-extra";
|
|
201
|
+
|
|
202
|
+
// src/project.ts
|
|
203
|
+
import path8 from "path";
|
|
204
|
+
|
|
205
|
+
// src/version.ts
|
|
206
|
+
import fs6 from "fs-extra";
|
|
207
|
+
import path7 from "path";
|
|
208
|
+
|
|
209
|
+
// src/project.ts
|
|
210
|
+
import fs7 from "fs-extra";
|
|
211
|
+
|
|
212
|
+
// src/doctor.ts
|
|
175
213
|
var DOTNET = process.platform === "win32" ? "dotnet.exe" : "dotnet";
|
|
176
214
|
var MAUI_DOCS = "https://learn.microsoft.com/dotnet/maui/get-started/installation";
|
|
177
215
|
var INSTALL_NET_10_FIX = "Install the .NET 10 SDK \u2014 https://dotnet.microsoft.com/download";
|
|
178
216
|
var bufToStr = (v) => v == null ? "" : Buffer.isBuffer(v) ? v.toString() : v;
|
|
179
217
|
var run = (cmd, args) => {
|
|
180
218
|
try {
|
|
181
|
-
const stdout =
|
|
219
|
+
const stdout = execFileSync5(cmd, args, {
|
|
182
220
|
encoding: "utf-8",
|
|
183
221
|
stdio: ["ignore", "pipe", "pipe"]
|
|
184
222
|
});
|
|
@@ -244,7 +282,7 @@ var installWorkload = (csprojPath) => {
|
|
|
244
282
|
);
|
|
245
283
|
console.log();
|
|
246
284
|
try {
|
|
247
|
-
|
|
285
|
+
execFileSync5(DOTNET, args, { stdio: "inherit" });
|
|
248
286
|
return true;
|
|
249
287
|
} catch {
|
|
250
288
|
console.error();
|
|
@@ -322,15 +360,17 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
322
360
|
|
|
323
361
|
// src/index.ts
|
|
324
362
|
var note = (label, body) => ` ${dim(label.padEnd(7))} ${body}`;
|
|
325
|
-
var __dirname =
|
|
326
|
-
var CLI_ROOT =
|
|
327
|
-
var TEMPLATES_DIR =
|
|
328
|
-
var VIDRA_REPO_ROOT =
|
|
329
|
-
var LOCAL_FEED_DIR =
|
|
363
|
+
var __dirname = path10.dirname(fileURLToPath(import.meta.url));
|
|
364
|
+
var CLI_ROOT = path10.resolve(__dirname, "..");
|
|
365
|
+
var TEMPLATES_DIR = path10.join(CLI_ROOT, "templates");
|
|
366
|
+
var VIDRA_REPO_ROOT = path10.resolve(CLI_ROOT, "..", "..", "..");
|
|
367
|
+
var LOCAL_FEED_DIR = path10.join(VIDRA_REPO_ROOT, "dist", "packages");
|
|
330
368
|
var LOCAL_CLI_DIR = CLI_ROOT;
|
|
331
|
-
var LOCAL_SDK_DIR =
|
|
332
|
-
var VIDRA_VERSION =
|
|
333
|
-
|
|
369
|
+
var LOCAL_SDK_DIR = path10.join(VIDRA_REPO_ROOT, "src", "sdk", "vidra-js");
|
|
370
|
+
var VIDRA_VERSION = JSON.parse(
|
|
371
|
+
fs9.readFileSync(path10.join(CLI_ROOT, "package.json"), "utf-8")
|
|
372
|
+
).version;
|
|
373
|
+
var SDK_VERSION = VIDRA_VERSION;
|
|
334
374
|
var main = async () => {
|
|
335
375
|
console.log();
|
|
336
376
|
console.log(` create-${lime("vidra")}-app`);
|
|
@@ -369,8 +409,8 @@ var main = async () => {
|
|
|
369
409
|
);
|
|
370
410
|
appId = res.appId;
|
|
371
411
|
}
|
|
372
|
-
const root =
|
|
373
|
-
if (
|
|
412
|
+
const root = path10.resolve(projectDir);
|
|
413
|
+
if (fs9.existsSync(root) && fs9.readdirSync(root).length > 0) {
|
|
374
414
|
console.error();
|
|
375
415
|
console.error(
|
|
376
416
|
row({
|
|
@@ -386,8 +426,8 @@ var main = async () => {
|
|
|
386
426
|
console.log(kv("directory", root));
|
|
387
427
|
console.log(kv("app id", appId));
|
|
388
428
|
console.log();
|
|
389
|
-
const isMonorepo =
|
|
390
|
-
const localFeedExists = isMonorepo &&
|
|
429
|
+
const isMonorepo = fs9.existsSync(path10.join(LOCAL_SDK_DIR, "package.json"));
|
|
430
|
+
const localFeedExists = isMonorepo && fs9.existsSync(LOCAL_FEED_DIR);
|
|
391
431
|
const localFeedSource = localFeedExists ? ` <add key="vidra-local" value="${toTextPath(LOCAL_FEED_DIR)}" />` : "";
|
|
392
432
|
const cliRef = isMonorepo ? `file:${toTextPath(LOCAL_CLI_DIR)}` : `^${VIDRA_VERSION}`;
|
|
393
433
|
const sdkRef = isMonorepo ? `file:${toTextPath(LOCAL_SDK_DIR)}` : `^${SDK_VERSION}`;
|
|
@@ -402,17 +442,17 @@ var main = async () => {
|
|
|
402
442
|
"{{sdkVersion}}": sdkRef,
|
|
403
443
|
"{{localFeedSource}}": localFeedSource
|
|
404
444
|
};
|
|
405
|
-
const templateDir =
|
|
445
|
+
const templateDir = path10.join(TEMPLATES_DIR, "react-vite");
|
|
406
446
|
await scaffoldDir(templateDir, root, replacements);
|
|
407
447
|
console.log(row({ glyph: "active", detail: dim("creating solution\u2026") }));
|
|
408
448
|
exec(`dotnet new sln -n ${projectName} --force`, root);
|
|
409
|
-
const slnFile =
|
|
449
|
+
const slnFile = fs9.existsSync(path10.join(root, `${projectName}.slnx`)) ? `${projectName}.slnx` : `${projectName}.sln`;
|
|
410
450
|
exec(
|
|
411
451
|
`dotnet sln ${slnFile} add src/${projectName}.Host/${projectName}.Host.csproj`,
|
|
412
452
|
root
|
|
413
453
|
);
|
|
414
454
|
console.log(row({ glyph: "active", detail: dim("installing dependencies\u2026") }));
|
|
415
|
-
const uiDir =
|
|
455
|
+
const uiDir = path10.join(root, "ui");
|
|
416
456
|
const [rootNpmOk, uiNpmOk] = await Promise.all([
|
|
417
457
|
tryExecAsync("npm install", root),
|
|
418
458
|
tryExecAsync("npm install", uiDir)
|
|
@@ -450,7 +490,7 @@ var main = async () => {
|
|
|
450
490
|
);
|
|
451
491
|
console.log();
|
|
452
492
|
}
|
|
453
|
-
const hostCsproj =
|
|
493
|
+
const hostCsproj = path10.join(
|
|
454
494
|
root,
|
|
455
495
|
"src",
|
|
456
496
|
`${projectName}.Host`,
|
package/package.json
CHANGED
|
@@ -31,17 +31,24 @@ npm run dev
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
This starts the Vite dev server and launches the native host for the current OS
|
|
34
|
-
under `dotnet watch`. Both sides of the app
|
|
34
|
+
under `dotnet watch`. Both sides of the app pick up your edits:
|
|
35
35
|
|
|
36
36
|
- **UI**: edit anything in `ui/src` — Vite HMR updates the WebView instantly.
|
|
37
|
-
- **C#**: edit the host (for example `OnTickAsync` in `MainPage.cs`) —
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
- **C#**: edit the host (for example `OnTickAsync` in `MainPage.cs`) and save —
|
|
38
|
+
the session puts the change in front of you in seconds. *How* depends on the
|
|
39
|
+
platform:
|
|
40
|
+
- **Windows**: supported edits apply to the *running* app and the UI flashes a
|
|
41
|
+
"C# reloaded" badge. Edits hot reload can't express (new fields, changed
|
|
42
|
+
signatures, …) trigger an automatic rebuild and relaunch.
|
|
43
|
+
- **macOS**: the same, when the toolchain cooperates. Mac Catalyst's
|
|
44
|
+
hot-reload agent often drops its connection mid-session (dotnet/sdk#55488);
|
|
45
|
+
a dropped agent applies nothing while `dotnet watch` still reports success,
|
|
46
|
+
so `vidra dev` watches for it and switches the session to rebuild +
|
|
47
|
+
relaunch on save. You'll see it say so — after that, edits arrive with a
|
|
48
|
+
restart and no badge.
|
|
49
|
+
`npm run doctor` says which loop you get.
|
|
50
|
+
|
|
51
|
+
To skip `dotnet watch` entirely and do a single build and launch:
|
|
45
52
|
|
|
46
53
|
```bash
|
|
47
54
|
npx vidra dev --no-hot-reload
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>com.apple.security.cs.allow-jit</key>
|
|
6
|
+
<true/>
|
|
7
|
+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
|
8
|
+
<true/>
|
|
9
|
+
<key>com.apple.security.cs.disable-library-validation</key>
|
|
10
|
+
<true/>
|
|
11
|
+
<key>com.apple.security.network.client</key>
|
|
12
|
+
<true/>
|
|
13
|
+
<key>com.apple.security.files.user-selected.read-write</key>
|
|
14
|
+
<true/>
|
|
15
|
+
<key>com.apple.security.app-sandbox</key>
|
|
16
|
+
<false/>
|
|
17
|
+
</dict>
|
|
18
|
+
</plist>
|
|
@@ -9,6 +9,25 @@ public static class MauiProgram
|
|
|
9
9
|
{
|
|
10
10
|
var builder = MauiApp.CreateBuilder();
|
|
11
11
|
|
|
12
|
+
// Updates come in two tiers. Both are opt-in and both read one
|
|
13
|
+
// `vidra.updates` block in package.json.
|
|
14
|
+
//
|
|
15
|
+
// Web bundle: fast, no reinstall. Add `.UseVidraUpdates()` below and
|
|
16
|
+
//
|
|
17
|
+
// "vidra": { "updates": { "feedUrl": "https://example.com/bundles.json" } }
|
|
18
|
+
//
|
|
19
|
+
// then publish with `npx vidra bundle`. A bundle only installs when its
|
|
20
|
+
// contract fingerprints match this build, so JS can never call a bridge
|
|
21
|
+
// the installed binary lacks.
|
|
22
|
+
//
|
|
23
|
+
// Whole app: native code included. Reference Vidra.Updates.Native, add
|
|
24
|
+
// `.UseVidraNativeUpdates()`, uncomment the line in Platforms/*/Program.cs,
|
|
25
|
+
// and add
|
|
26
|
+
//
|
|
27
|
+
// "vidra": { "updates": { "native": { "feedUrl": "https://example.com/app/" } } }
|
|
28
|
+
//
|
|
29
|
+
// then build with `npx vidra build --target <target> --native-update`.
|
|
30
|
+
// `npx vidra doctor` names whichever half is missing.
|
|
12
31
|
builder
|
|
13
32
|
.UseMauiApp<App>()
|
|
14
33
|
.UseVidra()
|
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
// The app's entry point on Mac Catalyst.
|
|
2
|
+
//
|
|
3
|
+
// A native updater has to run before UIKit does: on install, update and
|
|
4
|
+
// uninstall Velopack re-launches the app with a `--veloapp-*` argument and
|
|
5
|
+
// expects it to do that work and exit without ever showing a window. `vpk pack`
|
|
6
|
+
// also inspects the assembly statically and warns when
|
|
7
|
+
// `VelopackApp.Build()...Run()` is anywhere other than the entry point.
|
|
8
|
+
//
|
|
9
|
+
// `UseVidraLocator()` is the Mac Catalyst part. Velopack's client picks its
|
|
10
|
+
// locator from `RuntimeInformation.IsOSPlatform`, which answers false for OSX
|
|
11
|
+
// here, so without it, `Run()` throws before any update logic executes.
|
|
12
|
+
//
|
|
13
|
+
// To turn native updates on:
|
|
14
|
+
// 1. add the Vidra.Updates.Native package reference to this project
|
|
15
|
+
// 2. uncomment the two lines below, and the ones in MauiProgram.cs
|
|
16
|
+
// 3. add a `vidra.updates.native.feedUrl` to package.json
|
|
17
|
+
// 4. build with `npx vidra build --target macos --native-update`
|
|
18
|
+
//
|
|
19
|
+
// `npx vidra doctor` checks all four and names whichever is missing.
|
|
20
|
+
|
|
21
|
+
// using Velopack;
|
|
22
|
+
// using Vidra.Hosting;
|
|
1
23
|
using UIKit;
|
|
2
24
|
|
|
3
25
|
namespace {{projectName}};
|
|
@@ -6,6 +28,8 @@ public static class Program
|
|
|
6
28
|
{
|
|
7
29
|
static void Main(string[] args)
|
|
8
30
|
{
|
|
31
|
+
// VelopackApp.Build().UseVidraLocator().Run();
|
|
32
|
+
|
|
9
33
|
UIApplication.Main(args, null, typeof(AppDelegate));
|
|
10
34
|
}
|
|
11
35
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// The app's real entry point on Windows.
|
|
2
|
+
//
|
|
3
|
+
// MAUI generates one of these for you. This app takes it over, via
|
|
4
|
+
// `<DefineConstants>` in the csproj setting DISABLE_XAML_GENERATED_MAIN, for
|
|
5
|
+
// one reason: a native updater has to run *first*, before any UI framework
|
|
6
|
+
// starts.
|
|
7
|
+
//
|
|
8
|
+
// On install, update and uninstall, Velopack re-launches the app with a
|
|
9
|
+
// `--veloapp-*` argument and expects it to do that work and exit without ever
|
|
10
|
+
// showing a window. `VelopackApp.Build()...Run()` is what handles those launches,
|
|
11
|
+
// and `vpk pack` statically inspects the assembly and warns when it finds the
|
|
12
|
+
// call anywhere other than the entry point. Putting it here costs nothing and
|
|
13
|
+
// means an app that later enables updates needs no migration into generated code.
|
|
14
|
+
//
|
|
15
|
+
// To turn native updates on:
|
|
16
|
+
// 1. add the Vidra.Updates.Native package reference to this project
|
|
17
|
+
// 2. uncomment the two lines below, and the ones in MauiProgram.cs
|
|
18
|
+
// 3. add a `vidra.updates.native.feedUrl` to package.json
|
|
19
|
+
// 4. build with `npx vidra build --target windows --native-update`
|
|
20
|
+
//
|
|
21
|
+
// `npx vidra doctor` checks all four and names whichever is missing.
|
|
22
|
+
|
|
23
|
+
// using Velopack;
|
|
24
|
+
// using Vidra.Hosting;
|
|
25
|
+
|
|
26
|
+
namespace {{projectName}}.WinUI;
|
|
27
|
+
|
|
28
|
+
public static class Program
|
|
29
|
+
{
|
|
30
|
+
[STAThread]
|
|
31
|
+
static void Main(string[] args)
|
|
32
|
+
{
|
|
33
|
+
// VelopackApp.Build().UseVidraLocator().Run();
|
|
34
|
+
|
|
35
|
+
WinRT.ComWrappersSupport.InitializeComWrappers();
|
|
36
|
+
|
|
37
|
+
Microsoft.UI.Xaml.Application.Start(p =>
|
|
38
|
+
{
|
|
39
|
+
var context = new Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext(
|
|
40
|
+
Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());
|
|
41
|
+
System.Threading.SynchronizationContext.SetSynchronizationContext(context);
|
|
42
|
+
_ = new App();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -18,6 +18,28 @@
|
|
|
18
18
|
<ApplicationVersion>1</ApplicationVersion>
|
|
19
19
|
<ApplicationDisplayVersion>0.1.0</ApplicationDisplayVersion>
|
|
20
20
|
<EnableCodeSigning Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">true</EnableCodeSigning>
|
|
21
|
+
<!--
|
|
22
|
+
Entitlements for the hardened runtime, which notarization requires and
|
|
23
|
+
which would otherwise kill .NET's JIT. `vidra build` re-signs the bundle
|
|
24
|
+
with this same file, so pointing MAUI at it keeps both passes consistent.
|
|
25
|
+
|
|
26
|
+
What Entitlements.plist grants (it carries no comments of its own — the
|
|
27
|
+
MacCatalyst SDK's plist parser rejects XML comments inside <dict>):
|
|
28
|
+
allow-jit + allow-unsigned-executable-memory .NET compiles to
|
|
29
|
+
writable-then-executable memory
|
|
30
|
+
disable-library-validation the runtime loads dylibs
|
|
31
|
+
signed by another team
|
|
32
|
+
network.client the WebView reaches the
|
|
33
|
+
Vite dev server
|
|
34
|
+
files.user-selected.read-write filePicker hands back paths
|
|
35
|
+
the app then reads
|
|
36
|
+
app-sandbox = false Vidra's filesystem module
|
|
37
|
+
exposes unrestricted paths;
|
|
38
|
+
Developer ID (unlike the App
|
|
39
|
+
Store) does not require the
|
|
40
|
+
sandbox
|
|
41
|
+
-->
|
|
42
|
+
<CodesignEntitlements Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">Entitlements.plist</CodesignEntitlements>
|
|
21
43
|
|
|
22
44
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
|
|
23
45
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
|
|
@@ -31,6 +53,21 @@
|
|
|
31
53
|
-->
|
|
32
54
|
<WindowsPackageType Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">None</WindowsPackageType>
|
|
33
55
|
|
|
56
|
+
<!--
|
|
57
|
+
This app owns its Windows entry point (Platforms/Windows/Program.cs)
|
|
58
|
+
instead of the one the XAML compiler generates.
|
|
59
|
+
|
|
60
|
+
A native updater has to run before any UI framework starts: on install,
|
|
61
|
+
update and uninstall Velopack re-launches the app with a `veloapp`
|
|
62
|
+
argument and expects it to do that work and exit without ever showing a
|
|
63
|
+
window, and `vpk pack` inspects the assembly and warns when it finds the
|
|
64
|
+
call outside the entry point. Entry-point shape is the one thing a package
|
|
65
|
+
reference cannot retrofit, so every Vidra app ships with it and the
|
|
66
|
+
Velopack line stays commented out until the app opts in. Mac Catalyst
|
|
67
|
+
already has a real `Main`, so it needs no equivalent switch.
|
|
68
|
+
-->
|
|
69
|
+
<DefineConstants Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
|
|
70
|
+
|
|
34
71
|
<!--
|
|
35
72
|
Skip the MacCatalyst managed linker in Debug. The linker's Setup step
|
|
36
73
|
validates the MacCatalyst SDK headers against the maui workload version,
|