@swifttui/build 0.17.0 → 0.18.1

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 CHANGED
@@ -6,8 +6,9 @@ compile a SwiftTUI app to `wasm32-wasi` and capture its scene manifest.**
6
6
  [![npm](https://img.shields.io/npm/v/@swifttui/build)](https://www.npmjs.com/package/@swifttui/build)
7
7
  ![License](https://img.shields.io/badge/license-MIT-3DA639)
8
8
 
9
- `@swifttui/build` produces an `app.wasm`, a `scene-manifest.json`, and the DOM
10
- host's bundled font assets and license notice. It drives the Swift toolchain, runs a
9
+ `@swifttui/build` produces an `app.wasm` and a `scene-manifest.json`.
10
+ Canvas is the default; `--renderer dom` additionally packages the experimental
11
+ DOM host's font assets and license notice. It drives the Swift toolchain, runs a
11
12
  browser `WebAssembly.compile` validation pass, and packages the result. It
12
13
  is separate from [`@swifttui/web`](https://www.npmjs.com/package/@swifttui/web),
13
14
  the browser runtime. Thus, runtime imports do not include Swift processes, Node
@@ -53,14 +54,60 @@ await buildSwiftTUIWebApp({
53
54
  });
54
55
  ```
55
56
 
56
- The full build copies the runtime package's four verified WOFF2 faces, their
57
- manifest and OFL notice into `assets/swifttui-fonts/6ec060766aae/`. Deploy that
57
+ For experimental DOM, pass `--renderer dom` to the command or `renderer: "dom"`
58
+ to `buildSwiftTUIWebApp`. That build copies the runtime package's four verified WOFF2 faces, their
59
+ manifest and OFL notice into `assets/swifttui-fonts/7d231a426067/`. Deploy that
58
60
  directory with the app. Build systems that package WASM separately can use
59
61
  `await copyDomFontAssets(outputDirectory)` from `@swifttui/build`; it validates
60
62
  the installed asset hashes before copying. Runtime `domFont.assetBase` can
61
63
  point at another same-origin asset directory. Font loading does not depend on
62
64
  an external font service.
63
65
 
66
+ ### Choose the browser renderer
67
+
68
+ The WASM/manifest build above is independent of browser JavaScript bundling.
69
+ For the standalone WebHost page, including a custom native app companion,
70
+ install Bun and run:
71
+
72
+ ```sh
73
+ npx swifttui-web build:web --renderer canvas --dist browser
74
+ npx swifttui-web build:web --renderer dom --dist browser-dom
75
+ ```
76
+
77
+ `build:web` needs no `--app`, Swift compiler, or WASM build. It produces
78
+ `index.html` and JavaScript with only the selected painter; the DOM variant also
79
+ includes its fonts and license. Omitting `--renderer` selects Canvas. Rebuilding
80
+ the same output directory replaces the previous presenter and removes DOM fonts
81
+ when selecting Canvas. Serve the entire directory. A native SwiftTUI app can
82
+ set `RuntimeConfiguration.browserAssetsPath` to that directory to use it for
83
+ both its accessibility companion and `--web` mode.
84
+
85
+ The API equivalent is:
86
+
87
+ ```ts
88
+ import { buildBrowserBundle } from "@swifttui/build";
89
+ await buildBrowserBundle({ outputDirectory: "browser-dom", renderer: "dom" });
90
+ ```
91
+
92
+ For a custom web page with its own bundler, set the bundler's compile-time
93
+ `SWIFTTUI_WEB_RENDERER` define to `JSON.stringify("canvas")` or
94
+ `JSON.stringify("dom")` and enable dead-code elimination. In Vite, for example:
95
+
96
+ ```ts
97
+ export default {
98
+ define: { SWIFTTUI_WEB_RENDERER: JSON.stringify("dom") },
99
+ };
100
+ ```
101
+
102
+ Use `renderer: "dom"` in `createWebHostApp` (or omit it in a DOM-only build),
103
+ and package fonts with `build --renderer dom` or `copyDomFontAssets`.
104
+ Canvas-only builds need no DOM font copy. An unconfigured library bundle retains
105
+ both renderers for runtime selection and defaults to Canvas; the explicit build
106
+ define is what excludes the unused implementation. A single-renderer build
107
+ rejects requests for the other renderer, including URL or page configuration
108
+ overrides. DOM remains experimental; see the runtime's
109
+ [renderer guide](../web/README.md#renderers).
110
+
64
111
  Toolchain defaults match the repo:
65
112
 
66
113
  - Swift command: `swiftly run swift` when `swiftly` is on `PATH`, otherwise
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { buildAppWasm } from "./src/build/buildAppWasm.js";
3
+ import { buildBrowserBundle, parseWebRenderer } from "./src/build/buildBrowserBundle.js";
3
4
  import { generateSceneManifest } from "./src/build/generateSceneManifest.js";
4
5
  import { buildSwiftTUIWebApp } from "./src/build/buildSwiftTUIWebApp.js";
5
6
  import { resolve } from "node:path";
@@ -10,9 +11,16 @@ async function runCli(argv) {
10
11
  const flags = parseFlags(argv.slice(1));
11
12
  const packagePath = resolve(flags["package-path"] ?? "../../");
12
13
  const distPath = resolve(flags["dist"] ?? "./dist");
14
+ const renderer = parseWebRenderer(flags.renderer);
13
15
  const appExecutable = flags.app ?? flags.product ?? flags["app-product"] ?? "";
14
16
  const configuration = parseWasmBuildConfiguration(flags.configuration ?? "release");
15
17
  switch (command) {
18
+ case "build:web":
19
+ await buildBrowserBundle({
20
+ outputDirectory: distPath,
21
+ renderer
22
+ });
23
+ return;
16
24
  case "build:manifest":
17
25
  assertAppExecutable(appExecutable);
18
26
  await generateSceneManifest({
@@ -33,6 +41,7 @@ async function runCli(argv) {
33
41
  case "build":
34
42
  assertAppExecutable(appExecutable);
35
43
  await buildSwiftTUIWebApp({
44
+ renderer,
36
45
  configuration,
37
46
  packagePath,
38
47
  outputDirectory: distPath,
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { resolve } from \"node:path\";\nimport {\n buildAppWasm,\n buildSwiftTUIWebApp,\n generateSceneManifest,\n type WasmBuildConfiguration,\n} from \"./index.ts\";\n\nvoid runCli(process.argv.slice(2));\n\nasync function runCli(argv: string[]): Promise<void> {\n const command = argv[0] ?? \"build\";\n const flags = parseFlags(argv.slice(1));\n const packagePath = resolve(flags[\"package-path\"] ?? \"../../\");\n const distPath = resolve(flags[\"dist\"] ?? \"./dist\");\n const appExecutable =\n flags.app ?? flags.product ?? flags[\"app-product\"] ?? \"\";\n const configuration = parseWasmBuildConfiguration(\n flags.configuration ?? \"release\",\n );\n\n switch (command) {\n case \"build:manifest\":\n assertAppExecutable(appExecutable);\n await generateSceneManifest({\n packagePath,\n outputPath: resolve(distPath, \"scene-manifest.json\"),\n appExecutable,\n });\n return;\n case \"build:wasm\":\n assertAppExecutable(appExecutable);\n await buildAppWasm({\n configuration,\n packagePath,\n outputDirectory: distPath,\n product: appExecutable,\n });\n return;\n case \"build\":\n assertAppExecutable(appExecutable);\n await buildSwiftTUIWebApp({\n configuration,\n packagePath,\n outputDirectory: distPath,\n product: appExecutable,\n });\n return;\n default:\n throw new Error(`unknown command: ${command}`);\n }\n}\n\nfunction parseFlags(argv: string[]): Record<string, string> {\n const flags: Record<string, string> = {};\n for (let index = 0; index < argv.length; index += 1) {\n const value = argv[index];\n if (!value.startsWith(\"--\")) {\n continue;\n }\n const equalsIndex = value.indexOf(\"=\");\n if (equalsIndex !== -1) {\n flags[value.slice(2, equalsIndex)] = value.slice(equalsIndex + 1);\n continue;\n }\n const name = value.slice(2);\n const next = argv[index + 1];\n if (next && !next.startsWith(\"--\")) {\n flags[name] = next;\n index += 1;\n } else {\n flags[name] = \"true\";\n }\n }\n return flags;\n}\n\nfunction parseWasmBuildConfiguration(value: string): WasmBuildConfiguration {\n switch (value) {\n case \"debug\":\n return \"debug\";\n case \"release\":\n return \"release\";\n default:\n throw new Error(`unsupported wasm build configuration: ${value}`);\n }\n}\n\nfunction assertAppExecutable(value: string): asserts value is string {\n if (!value) {\n throw new Error(\"missing --app or --product flag\");\n }\n}\n"],"mappings":";;;;;;AAUK,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC;AAEjC,eAAe,OAAO,MAA+B;CACnD,MAAM,UAAU,KAAK,MAAM;CAC3B,MAAM,QAAQ,WAAW,KAAK,MAAM,CAAC,CAAC;CACtC,MAAM,cAAc,QAAQ,MAAM,mBAAmB,QAAQ;CAC7D,MAAM,WAAW,QAAQ,MAAM,WAAW,QAAQ;CAClD,MAAM,gBACJ,MAAM,OAAO,MAAM,WAAW,MAAM,kBAAkB;CACxD,MAAM,gBAAgB,4BACpB,MAAM,iBAAiB,SACzB;CAEA,QAAQ,SAAR;EACE,KAAK;GACH,oBAAoB,aAAa;GACjC,MAAM,sBAAsB;IAC1B;IACA,YAAY,QAAQ,UAAU,qBAAqB;IACnD;GACF,CAAC;GACD;EACF,KAAK;GACH,oBAAoB,aAAa;GACjC,MAAM,aAAa;IACjB;IACA;IACA,iBAAiB;IACjB,SAAS;GACX,CAAC;GACD;EACF,KAAK;GACH,oBAAoB,aAAa;GACjC,MAAM,oBAAoB;IACxB;IACA;IACA,iBAAiB;IACjB,SAAS;GACX,CAAC;GACD;EACF,SACE,MAAM,IAAI,MAAM,oBAAoB,SAAS;CACjD;AACF;AAEA,SAAS,WAAW,MAAwC;CAC1D,MAAM,QAAgC,CAAC;CACvC,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;EACnD,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,MAAM,WAAW,IAAI,GACxB;EAEF,MAAM,cAAc,MAAM,QAAQ,GAAG;EACrC,IAAI,gBAAgB,IAAI;GACtB,MAAM,MAAM,MAAM,GAAG,WAAW,KAAK,MAAM,MAAM,cAAc,CAAC;GAChE;EACF;EACA,MAAM,OAAO,MAAM,MAAM,CAAC;EAC1B,MAAM,OAAO,KAAK,QAAQ;EAC1B,IAAI,QAAQ,CAAC,KAAK,WAAW,IAAI,GAAG;GAClC,MAAM,QAAQ;GACd,SAAS;EACX,OACE,MAAM,QAAQ;CAElB;CACA,OAAO;AACT;AAEA,SAAS,4BAA4B,OAAuC;CAC1E,QAAQ,OAAR;EACE,KAAK,SACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,SACE,MAAM,IAAI,MAAM,yCAAyC,OAAO;CACpE;AACF;AAEA,SAAS,oBAAoB,OAAwC;CACnE,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,iCAAiC;AAErD"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { resolve } from \"node:path\";\nimport {\n buildAppWasm,\n buildBrowserBundle,\n buildSwiftTUIWebApp,\n generateSceneManifest,\n parseWebRenderer,\n type WasmBuildConfiguration,\n} from \"./index.ts\";\n\nvoid runCli(process.argv.slice(2));\n\nasync function runCli(argv: string[]): Promise<void> {\n const command = argv[0] ?? \"build\";\n const flags = parseFlags(argv.slice(1));\n const packagePath = resolve(flags[\"package-path\"] ?? \"../../\");\n const distPath = resolve(flags[\"dist\"] ?? \"./dist\");\n const renderer = parseWebRenderer(flags.renderer);\n const appExecutable =\n flags.app ?? flags.product ?? flags[\"app-product\"] ?? \"\";\n const configuration = parseWasmBuildConfiguration(\n flags.configuration ?? \"release\",\n );\n\n switch (command) {\n case \"build:web\":\n await buildBrowserBundle({ outputDirectory: distPath, renderer });\n return;\n case \"build:manifest\":\n assertAppExecutable(appExecutable);\n await generateSceneManifest({\n packagePath,\n outputPath: resolve(distPath, \"scene-manifest.json\"),\n appExecutable,\n });\n return;\n case \"build:wasm\":\n assertAppExecutable(appExecutable);\n await buildAppWasm({\n configuration,\n packagePath,\n outputDirectory: distPath,\n product: appExecutable,\n });\n return;\n case \"build\":\n assertAppExecutable(appExecutable);\n await buildSwiftTUIWebApp({\n renderer,\n configuration,\n packagePath,\n outputDirectory: distPath,\n product: appExecutable,\n });\n return;\n default:\n throw new Error(`unknown command: ${command}`);\n }\n}\n\nfunction parseFlags(argv: string[]): Record<string, string> {\n const flags: Record<string, string> = {};\n for (let index = 0; index < argv.length; index += 1) {\n const value = argv[index];\n if (!value.startsWith(\"--\")) {\n continue;\n }\n const equalsIndex = value.indexOf(\"=\");\n if (equalsIndex !== -1) {\n flags[value.slice(2, equalsIndex)] = value.slice(equalsIndex + 1);\n continue;\n }\n const name = value.slice(2);\n const next = argv[index + 1];\n if (next && !next.startsWith(\"--\")) {\n flags[name] = next;\n index += 1;\n } else {\n flags[name] = \"true\";\n }\n }\n return flags;\n}\n\nfunction parseWasmBuildConfiguration(value: string): WasmBuildConfiguration {\n switch (value) {\n case \"debug\":\n return \"debug\";\n case \"release\":\n return \"release\";\n default:\n throw new Error(`unsupported wasm build configuration: ${value}`);\n }\n}\n\nfunction assertAppExecutable(value: string): asserts value is string {\n if (!value) {\n throw new Error(\"missing --app or --product flag\");\n }\n}\n"],"mappings":";;;;;;;AAYK,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC;AAEjC,eAAe,OAAO,MAA+B;CACnD,MAAM,UAAU,KAAK,MAAM;CAC3B,MAAM,QAAQ,WAAW,KAAK,MAAM,CAAC,CAAC;CACtC,MAAM,cAAc,QAAQ,MAAM,mBAAmB,QAAQ;CAC7D,MAAM,WAAW,QAAQ,MAAM,WAAW,QAAQ;CAClD,MAAM,WAAW,iBAAiB,MAAM,QAAQ;CAChD,MAAM,gBACJ,MAAM,OAAO,MAAM,WAAW,MAAM,kBAAkB;CACxD,MAAM,gBAAgB,4BACpB,MAAM,iBAAiB,SACzB;CAEA,QAAQ,SAAR;EACE,KAAK;GACH,MAAM,mBAAmB;IAAE,iBAAiB;IAAU;GAAS,CAAC;GAChE;EACF,KAAK;GACH,oBAAoB,aAAa;GACjC,MAAM,sBAAsB;IAC1B;IACA,YAAY,QAAQ,UAAU,qBAAqB;IACnD;GACF,CAAC;GACD;EACF,KAAK;GACH,oBAAoB,aAAa;GACjC,MAAM,aAAa;IACjB;IACA;IACA,iBAAiB;IACjB,SAAS;GACX,CAAC;GACD;EACF,KAAK;GACH,oBAAoB,aAAa;GACjC,MAAM,oBAAoB;IACxB;IACA;IACA;IACA,iBAAiB;IACjB,SAAS;GACX,CAAC;GACD;EACF,SACE,MAAM,IAAI,MAAM,oBAAoB,SAAS;CACjD;AACF;AAEA,SAAS,WAAW,MAAwC;CAC1D,MAAM,QAAgC,CAAC;CACvC,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;EACnD,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,MAAM,WAAW,IAAI,GACxB;EAEF,MAAM,cAAc,MAAM,QAAQ,GAAG;EACrC,IAAI,gBAAgB,IAAI;GACtB,MAAM,MAAM,MAAM,GAAG,WAAW,KAAK,MAAM,MAAM,cAAc,CAAC;GAChE;EACF;EACA,MAAM,OAAO,MAAM,MAAM,CAAC;EAC1B,MAAM,OAAO,KAAK,QAAQ;EAC1B,IAAI,QAAQ,CAAC,KAAK,WAAW,IAAI,GAAG;GAClC,MAAM,QAAQ;GACd,SAAS;EACX,OACE,MAAM,QAAQ;CAElB;CACA,OAAO;AACT;AAEA,SAAS,4BAA4B,OAAuC;CAC1E,QAAQ,OAAR;EACE,KAAK,SACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,SACE,MAAM,IAAI,MAAM,yCAAyC,OAAO;CACpE;AACF;AAEA,SAAS,oBAAoB,OAAwC;CACnE,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,iCAAiC;AAErD"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ResolveSwiftArtifactsOptions, SwiftArtifactPaths, WasmBuildConfiguration, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, hasRequiredWasmFlags, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines } from "./src/build/resolveSwiftArtifacts.js";
2
2
  import { BuildAppWasmOptions, buildAppWasm, packageBrowserValidatedWasm } from "./src/build/buildAppWasm.js";
3
+ import { BuildBrowserBundleOptions, WebRenderer, buildBrowserBundle, parseWebRenderer } from "./src/build/buildBrowserBundle.js";
3
4
  import { BuildSwiftTUIWebAppOptions, buildSwiftTUIWebApp } from "./src/build/buildSwiftTUIWebApp.js";
4
5
  import { copyDomFontAssets } from "./src/build/copyDomFontAssets.js";
5
6
  import { GenerateSceneManifestOptions, generateSceneManifest } from "./src/build/generateSceneManifest.js";
6
- export { BuildAppWasmOptions, BuildSwiftTUIWebAppOptions, GenerateSceneManifestOptions, ResolveSwiftArtifactsOptions, SwiftArtifactPaths, WasmBuildConfiguration, buildAppWasm, buildSwiftTUIWebApp, copyDomFontAssets, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, generateSceneManifest, hasRequiredWasmFlags, packageBrowserValidatedWasm, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines };
7
+ export { BuildAppWasmOptions, BuildBrowserBundleOptions, BuildSwiftTUIWebAppOptions, GenerateSceneManifestOptions, ResolveSwiftArtifactsOptions, SwiftArtifactPaths, WasmBuildConfiguration, WebRenderer, buildAppWasm, buildBrowserBundle, buildSwiftTUIWebApp, copyDomFontAssets, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, generateSceneManifest, hasRequiredWasmFlags, packageBrowserValidatedWasm, parseWebRenderer, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, hasRequiredWasmFlags, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines } from "./src/build/resolveSwiftArtifacts.js";
2
2
  import { buildAppWasm, packageBrowserValidatedWasm } from "./src/build/buildAppWasm.js";
3
3
  import { copyDomFontAssets } from "./src/build/copyDomFontAssets.js";
4
+ import { buildBrowserBundle, parseWebRenderer } from "./src/build/buildBrowserBundle.js";
4
5
  import { generateSceneManifest } from "./src/build/generateSceneManifest.js";
5
6
  import { buildSwiftTUIWebApp } from "./src/build/buildSwiftTUIWebApp.js";
6
- export { buildAppWasm, buildSwiftTUIWebApp, copyDomFontAssets, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, generateSceneManifest, hasRequiredWasmFlags, packageBrowserValidatedWasm, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines };
7
+ export { buildAppWasm, buildBrowserBundle, buildSwiftTUIWebApp, copyDomFontAssets, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, generateSceneManifest, hasRequiredWasmFlags, packageBrowserValidatedWasm, parseWebRenderer, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines };
@@ -0,0 +1,13 @@
1
+ //#region src/build/buildBrowserBundle.d.ts
2
+ type WebRenderer = "canvas" | "dom";
3
+ declare function parseWebRenderer(value?: string): WebRenderer;
4
+ interface BuildBrowserBundleOptions {
5
+ outputDirectory: string;
6
+ /** Canvas-only by default. DOM is experimental and explicitly packaged. */
7
+ renderer?: WebRenderer;
8
+ }
9
+ /** Bundles a browser page with only the chosen painter. Requires Bun on PATH. */
10
+ declare function buildBrowserBundle(options: BuildBrowserBundleOptions): Promise<void>;
11
+ //#endregion
12
+ export { BuildBrowserBundleOptions, WebRenderer, buildBrowserBundle, parseWebRenderer };
13
+ //# sourceMappingURL=buildBrowserBundle.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { runCommand } from "./runCommand.js";
2
+ import { copyDomFontAssets } from "./copyDomFontAssets.js";
3
+ import { mkdir, readdir, rm } from "node:fs/promises";
4
+ import { join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ //#region src/build/buildBrowserBundle.ts
7
+ function parseWebRenderer(value = "canvas") {
8
+ if (value === "canvas" || value === "dom") return value;
9
+ throw new Error(`unsupported web renderer: ${value}; expected canvas or dom`);
10
+ }
11
+ /** Bundles a browser page with only the chosen painter. Requires Bun on PATH. */
12
+ async function buildBrowserBundle(options) {
13
+ const renderer = parseWebRenderer(options.renderer);
14
+ const outputDirectory = resolve(options.outputDirectory);
15
+ const entrypoint = fileURLToPath(import.meta.resolve("@swifttui/web/browser.html"));
16
+ await mkdir(outputDirectory, { recursive: true });
17
+ for (const name of await readdir(outputDirectory)) if (/^(?:index|browser)(?:[-.].*)?\.(?:js|css|html)$/.test(name)) await rm(join(outputDirectory, name));
18
+ await rm(join(outputDirectory, "assets/swifttui-fonts"), {
19
+ recursive: true,
20
+ force: true
21
+ });
22
+ await runCommand([
23
+ "bun",
24
+ "build",
25
+ entrypoint,
26
+ "--outdir",
27
+ outputDirectory,
28
+ "--entry-naming",
29
+ "index.[ext]",
30
+ "--minify-syntax",
31
+ "--define",
32
+ `SWIFTTUI_WEB_RENDERER=${JSON.stringify(renderer)}`
33
+ ]);
34
+ if (renderer === "dom") await copyDomFontAssets(outputDirectory);
35
+ }
36
+ //#endregion
37
+ export { buildBrowserBundle, parseWebRenderer };
38
+
39
+ //# sourceMappingURL=buildBrowserBundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildBrowserBundle.js","names":[],"sources":["../../../src/build/buildBrowserBundle.ts"],"sourcesContent":["import { mkdir, readdir, rm } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { copyDomFontAssets } from \"./copyDomFontAssets.ts\";\nimport { runCommand } from \"./runCommand.ts\";\n\nexport type WebRenderer = \"canvas\" | \"dom\";\n\nexport function parseWebRenderer(value: string = \"canvas\"): WebRenderer {\n if (value === \"canvas\" || value === \"dom\") return value;\n throw new Error(`unsupported web renderer: ${value}; expected canvas or dom`);\n}\n\nexport interface BuildBrowserBundleOptions {\n outputDirectory: string;\n /** Canvas-only by default. DOM is experimental and explicitly packaged. */\n renderer?: WebRenderer;\n}\n\n/** Bundles a browser page with only the chosen painter. Requires Bun on PATH. */\nexport async function buildBrowserBundle(\n options: BuildBrowserBundleOptions,\n): Promise<void> {\n const renderer = parseWebRenderer(options.renderer);\n const outputDirectory = resolve(options.outputDirectory);\n const entrypoint = fileURLToPath(\n import.meta.resolve(\"@swifttui/web/browser.html\"),\n );\n await mkdir(outputDirectory, { recursive: true });\n // Remove previous generated presenters/fonts when switching renderers. Keep\n // the separately packaged scene manifest and WASM artifacts in this directory.\n for (const name of await readdir(outputDirectory)) {\n if (/^(?:index|browser)(?:[-.].*)?\\.(?:js|css|html)$/.test(name)) {\n await rm(join(outputDirectory, name));\n }\n }\n await rm(join(outputDirectory, \"assets/swifttui-fonts\"), {\n recursive: true,\n force: true,\n });\n await runCommand([\n \"bun\",\n \"build\",\n entrypoint,\n \"--outdir\",\n outputDirectory,\n \"--entry-naming\",\n \"index.[ext]\",\n \"--minify-syntax\",\n \"--define\",\n `SWIFTTUI_WEB_RENDERER=${JSON.stringify(renderer)}`,\n ]);\n if (renderer === \"dom\") await copyDomFontAssets(outputDirectory);\n}\n"],"mappings":";;;;;;AAQA,SAAgB,iBAAiB,QAAgB,UAAuB;CACtE,IAAI,UAAU,YAAY,UAAU,OAAO,OAAO;CAClD,MAAM,IAAI,MAAM,6BAA6B,MAAM,yBAAyB;AAC9E;;AASA,eAAsB,mBACpB,SACe;CACf,MAAM,WAAW,iBAAiB,QAAQ,QAAQ;CAClD,MAAM,kBAAkB,QAAQ,QAAQ,eAAe;CACvD,MAAM,aAAa,cACjB,OAAO,KAAK,QAAQ,4BAA4B,CAClD;CACA,MAAM,MAAM,iBAAiB,EAAE,WAAW,KAAK,CAAC;CAGhD,KAAK,MAAM,QAAQ,MAAM,QAAQ,eAAe,GAC9C,IAAI,kDAAkD,KAAK,IAAI,GAC7D,MAAM,GAAG,KAAK,iBAAiB,IAAI,CAAC;CAGxC,MAAM,GAAG,KAAK,iBAAiB,uBAAuB,GAAG;EACvD,WAAW;EACX,OAAO;CACT,CAAC;CACD,MAAM,WAAW;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,yBAAyB,KAAK,UAAU,QAAQ;CAClD,CAAC;CACD,IAAI,aAAa,OAAO,MAAM,kBAAkB,eAAe;AACjE"}
@@ -1,7 +1,10 @@
1
1
  import { BuildAppWasmOptions } from "./buildAppWasm.js";
2
+ import { WebRenderer } from "./buildBrowserBundle.js";
2
3
  //#region src/build/buildSwiftTUIWebApp.d.ts
3
4
  interface BuildSwiftTUIWebAppOptions extends BuildAppWasmOptions {
4
5
  appExecutable?: string;
6
+ /** Include the experimental DOM font assets only when explicitly selected. */
7
+ renderer?: WebRenderer;
5
8
  }
6
9
  declare function buildSwiftTUIWebApp(options: BuildSwiftTUIWebAppOptions): Promise<void>;
7
10
  //#endregion
@@ -1,10 +1,12 @@
1
1
  import { buildAppWasm } from "./buildAppWasm.js";
2
2
  import { copyDomFontAssets } from "./copyDomFontAssets.js";
3
+ import { parseWebRenderer } from "./buildBrowserBundle.js";
3
4
  import { generateSceneManifest } from "./generateSceneManifest.js";
4
5
  import { mkdir, rm } from "node:fs/promises";
5
6
  import { join } from "node:path";
6
7
  //#region src/build/buildSwiftTUIWebApp.ts
7
8
  async function buildSwiftTUIWebApp(options) {
9
+ const renderer = parseWebRenderer(options.renderer);
8
10
  await rm(options.outputDirectory, {
9
11
  recursive: true,
10
12
  force: true
@@ -17,7 +19,7 @@ async function buildSwiftTUIWebApp(options) {
17
19
  swiftCommand: options.swiftCommand
18
20
  });
19
21
  await buildAppWasm(options);
20
- await copyDomFontAssets(options.outputDirectory);
22
+ if (renderer === "dom") await copyDomFontAssets(options.outputDirectory);
21
23
  }
22
24
  //#endregion
23
25
  export { buildSwiftTUIWebApp };
@@ -1 +1 @@
1
- {"version":3,"file":"buildSwiftTUIWebApp.js","names":[],"sources":["../../../src/build/buildSwiftTUIWebApp.ts"],"sourcesContent":["import { mkdir, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { type BuildAppWasmOptions, buildAppWasm } from \"./buildAppWasm.ts\";\nimport { copyDomFontAssets } from \"./copyDomFontAssets.ts\";\nimport { generateSceneManifest } from \"./generateSceneManifest.ts\";\n\nexport interface BuildSwiftTUIWebAppOptions extends BuildAppWasmOptions {\n appExecutable?: string;\n}\n\nexport async function buildSwiftTUIWebApp(\n options: BuildSwiftTUIWebAppOptions,\n): Promise<void> {\n await rm(options.outputDirectory, { recursive: true, force: true });\n await mkdir(options.outputDirectory, { recursive: true });\n await generateSceneManifest({\n packagePath: options.packagePath,\n outputPath: join(options.outputDirectory, \"scene-manifest.json\"),\n appExecutable: options.appExecutable ?? options.product,\n swiftCommand: options.swiftCommand,\n });\n await buildAppWasm(options);\n await copyDomFontAssets(options.outputDirectory);\n}\n"],"mappings":";;;;;;AAUA,eAAsB,oBACpB,SACe;CACf,MAAM,GAAG,QAAQ,iBAAiB;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAClE,MAAM,MAAM,QAAQ,iBAAiB,EAAE,WAAW,KAAK,CAAC;CACxD,MAAM,sBAAsB;EAC1B,aAAa,QAAQ;EACrB,YAAY,KAAK,QAAQ,iBAAiB,qBAAqB;EAC/D,eAAe,QAAQ,iBAAiB,QAAQ;EAChD,cAAc,QAAQ;CACxB,CAAC;CACD,MAAM,aAAa,OAAO;CAC1B,MAAM,kBAAkB,QAAQ,eAAe;AACjD"}
1
+ {"version":3,"file":"buildSwiftTUIWebApp.js","names":[],"sources":["../../../src/build/buildSwiftTUIWebApp.ts"],"sourcesContent":["import { mkdir, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { type BuildAppWasmOptions, buildAppWasm } from \"./buildAppWasm.ts\";\nimport { parseWebRenderer, type WebRenderer } from \"./buildBrowserBundle.ts\";\nimport { copyDomFontAssets } from \"./copyDomFontAssets.ts\";\nimport { generateSceneManifest } from \"./generateSceneManifest.ts\";\n\nexport interface BuildSwiftTUIWebAppOptions extends BuildAppWasmOptions {\n appExecutable?: string;\n /** Include the experimental DOM font assets only when explicitly selected. */\n renderer?: WebRenderer;\n}\n\nexport async function buildSwiftTUIWebApp(\n options: BuildSwiftTUIWebAppOptions,\n): Promise<void> {\n const renderer = parseWebRenderer(options.renderer);\n await rm(options.outputDirectory, { recursive: true, force: true });\n await mkdir(options.outputDirectory, { recursive: true });\n await generateSceneManifest({\n packagePath: options.packagePath,\n outputPath: join(options.outputDirectory, \"scene-manifest.json\"),\n appExecutable: options.appExecutable ?? options.product,\n swiftCommand: options.swiftCommand,\n });\n await buildAppWasm(options);\n if (renderer === \"dom\") await copyDomFontAssets(options.outputDirectory);\n}\n"],"mappings":";;;;;;;AAaA,eAAsB,oBACpB,SACe;CACf,MAAM,WAAW,iBAAiB,QAAQ,QAAQ;CAClD,MAAM,GAAG,QAAQ,iBAAiB;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAClE,MAAM,MAAM,QAAQ,iBAAiB,EAAE,WAAW,KAAK,CAAC;CACxD,MAAM,sBAAsB;EAC1B,aAAa,QAAQ;EACrB,YAAY,KAAK,QAAQ,iBAAiB,qBAAqB;EAC/D,eAAe,QAAQ,iBAAiB,QAAQ;EAChD,cAAc,QAAQ;CACxB,CAAC;CACD,MAAM,aAAa,OAAO;CAC1B,IAAI,aAAa,OAAO,MAAM,kBAAkB,QAAQ,eAAe;AACzE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swifttui/build",
3
- "version": "0.17.0",
3
+ "version": "0.18.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@swifttui/web": "0.17.0"
42
+ "@swifttui/web": "0.18.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/bun": "1.3.14"