From be03732baa102f8ae897b4f6769bc2e1fe45cb17 Mon Sep 17 00:00:00 2001 From: Mihaela Mihaljevic Date: Sat, 6 Jun 2026 22:06:38 +0200 Subject: [PATCH] feat: publish WASM streaming smoke site Add a browser WASM smoke site, four platform CI workflows, README status badges, and real file streaming coverage over the Geekbench corpus. --- .github/workflows/linux.yml | 16 +++ .github/workflows/{ci.yml => macos.yml} | 2 +- .github/workflows/wasm-site.yml | 110 +++++++++++++++++ .github/workflows/wasm.yml | 37 ++++++ .github/workflows/windows.yml | 24 ++++ .gitignore | 2 + Package.swift | 8 ++ README.md | 28 +++++ Sources/PureYAMLStreamingWasmSmoke/main.swift | 76 ++++++++++++ .../StreamingTests.swift | 80 ++++++++++-- WasmSite/index.html | 31 +++++ WasmSite/main.js | 115 ++++++++++++++++++ WasmSite/style.css | 94 ++++++++++++++ scripts/build-wasm-site.sh | 51 ++++++++ scripts/serve-wasm-site.sh | 8 ++ 15 files changed, 671 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/linux.yml rename .github/workflows/{ci.yml => macos.yml} (94%) create mode 100644 .github/workflows/wasm-site.yml create mode 100644 .github/workflows/wasm.yml create mode 100644 .github/workflows/windows.yml create mode 100644 Sources/PureYAMLStreamingWasmSmoke/main.swift create mode 100644 WasmSite/index.html create mode 100644 WasmSite/main.js create mode 100644 WasmSite/style.css create mode 100755 scripts/build-wasm-site.sh create mode 100755 scripts/serve-wasm-site.sh diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 0000000..2bf3d63 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,16 @@ +name: Linux + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + container: swift:6.2 + steps: + - uses: actions/checkout@v6 + - name: Build and test + run: bash scripts/check.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/macos.yml similarity index 94% rename from .github/workflows/ci.yml rename to .github/workflows/macos.yml index 82c429f..c39e5c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/macos.yml @@ -1,4 +1,4 @@ -name: CI +name: macOS on: push: diff --git a/.github/workflows/wasm-site.yml b/.github/workflows/wasm-site.yml new file mode 100644 index 0000000..d93a9b5 --- /dev/null +++ b/.github/workflows/wasm-site.yml @@ -0,0 +1,110 @@ +name: WASM Test Site + +on: + push: + branches: [main] + paths: + - "Package.swift" + - "Sources/PureYAMLStreaming/**" + - "Sources/PureYAMLStreamingWasmSmoke/**" + - "WasmSite/**" + - "scripts/build-wasm-site.sh" + - ".github/workflows/wasm-site.yml" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pureyaml-streaming-wasm-site + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install build tools + run: | + sudo apt-get update + sudo apt-get install -y binaryen gzip libcurl4-openssl-dev + + - name: Install swiftly + run: | + curl -L https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz > swiftly.tar.gz + tar zxf swiftly.tar.gz + ./swiftly init --quiet-shell-followup --assume-yes --skip-install + + - name: Install Swift 6.3.2 and Wasm SDK + run: | + . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" + swiftly install --use 6.3.2 + swiftly run swift sdk install https://download.swift.org/swift-6.3.2-release/wasm-sdk/swift-6.3.2-RELEASE/swift-6.3.2-RELEASE_wasm.artifactbundle.tar.gz --checksum a61f0584c93283589f8b2f42db05c1f9a182b506c2957271402992655591dd7c +6.3.2 + + - name: Build WASM site + run: | + . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" + bash scripts/build-wasm-site.sh + mkdir -p site + cp WasmSite/index.html site/index.html + cp WasmSite/main.js site/main.js + cp WasmSite/style.css site/style.css + cp WasmSite/pureyaml-streaming-wasm-smoke.wasm.gz site/pureyaml-streaming-wasm-smoke.wasm.gz + ls -lh site + + - name: Install Playwright Chromium + run: | + mkdir -p .build/playwright-ci + cd .build/playwright-ci + npm init -y + npm install playwright-chromium + npx playwright install --with-deps chromium + + - name: Test site locally + run: | + python3 -m http.server 8766 --bind 127.0.0.1 --directory site & + server_pid=$! + trap 'kill "$server_pid"' EXIT + node <<'NODE' + const { chromium } = require('./.build/playwright-ci/node_modules/playwright-chromium'); + + (async () => { + const browser = await chromium.launch({ headless: true }); + const page = await browser.newPage(); + await page.goto('http://127.0.0.1:8766/?v=' + Date.now()); + await page.click('#runButton'); + await page.waitForFunction( + () => document.querySelector('#status')?.textContent === 'Passed', + null, + { timeout: 60000 } + ); + const output = await page.locator('#output').textContent(); + if (!output.includes('"ok" : true') && !output.includes('"ok":true')) { + throw new Error(output); + } + await browser.close(); + })(); + NODE + + - name: Configure Pages + uses: actions/configure-pages@v5 + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: site + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml new file mode 100644 index 0000000..9775ea6 --- /dev/null +++ b/.github/workflows/wasm.yml @@ -0,0 +1,37 @@ +name: WASM + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Install build tools + run: | + sudo apt-get update + sudo apt-get install -y binaryen gzip libcurl4-openssl-dev + - name: Install swiftly + run: | + curl -L https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz > swiftly.tar.gz + tar zxf swiftly.tar.gz + ./swiftly init --quiet-shell-followup --assume-yes --skip-install + - name: Install Swift 6.3.2 and Wasm SDK + run: | + . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" + swiftly install --use 6.3.2 + swiftly run swift sdk install https://download.swift.org/swift-6.3.2-release/wasm-sdk/swift-6.3.2-RELEASE/swift-6.3.2-RELEASE_wasm.artifactbundle.tar.gz --checksum a61f0584c93283589f8b2f42db05c1f9a182b506c2957271402992655591dd7c +6.3.2 + - name: Build WASM smoke site + run: | + . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" + bash scripts/build-wasm-site.sh + - name: Upload WASM site artifact + uses: actions/upload-artifact@v6 + with: + name: pureyaml-streaming-wasm-site + path: WasmSite + retention-days: 7 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 0000000..c1e5047 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,24 @@ +name: Windows + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + test: + runs-on: windows-2022 + steps: + - uses: actions/checkout@v6 + - name: Install Swift + uses: compnerd/gha-setup-swift@main + with: + swift-version: swift-6.3.2-release + swift-build: 6.3.2-RELEASE + - name: Build + shell: pwsh + run: swift build + - name: Test + shell: pwsh + run: swift test diff --git a/.gitignore b/.gitignore index 29a1e94..d5dc969 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .build/ .swiftpm/ .DS_Store +WasmSite/*.wasm +WasmSite/*.wasm.gz diff --git a/Package.swift b/Package.swift index 699a08d..63dd559 100644 --- a/Package.swift +++ b/Package.swift @@ -12,6 +12,10 @@ let package = Package( name: "PureYAMLStreaming", targets: ["PureYAMLStreaming"], ), + .executable( + name: "pureyaml-streaming-wasm-smoke", + targets: ["PureYAMLStreamingWasmSmoke"], + ), ], dependencies: [ .package(url: "https://github.com/mihaelamj/PureYAML.git", branch: "main"), @@ -21,6 +25,10 @@ let package = Package( name: "PureYAMLStreaming", dependencies: ["PureYAML"], ), + .executableTarget( + name: "PureYAMLStreamingWasmSmoke", + dependencies: ["PureYAMLStreaming", "PureYAML"], + ), .testTarget( name: "PureYAMLStreamingTests", dependencies: ["PureYAMLStreaming"], diff --git a/README.md b/README.md index f92d167..05b1ae0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # PureYAMLStreaming +[![macOS](https://img.shields.io/github/actions/workflow/status/mihaelamj/PureYAMLStreaming/macos.yml?branch=main&label=macOS)](https://github.com/mihaelamj/PureYAMLStreaming/actions/workflows/macos.yml) +[![Linux](https://img.shields.io/github/actions/workflow/status/mihaelamj/PureYAMLStreaming/linux.yml?branch=main&label=Linux)](https://github.com/mihaelamj/PureYAMLStreaming/actions/workflows/linux.yml) +[![Windows](https://img.shields.io/github/actions/workflow/status/mihaelamj/PureYAMLStreaming/windows.yml?branch=main&label=Windows)](https://github.com/mihaelamj/PureYAMLStreaming/actions/workflows/windows.yml) +[![WASM](https://img.shields.io/github/actions/workflow/status/mihaelamj/PureYAMLStreaming/wasm.yml?branch=main&label=WASM)](https://github.com/mihaelamj/PureYAMLStreaming/actions/workflows/wasm.yml) +[![WASM Site](https://img.shields.io/github/actions/workflow/status/mihaelamj/PureYAMLStreaming/wasm-site.yml?branch=main&label=WASM%20Site)](https://github.com/mihaelamj/PureYAMLStreaming/actions/workflows/wasm-site.yml) + Experimental full-streaming incubator for PureYAML. This package is intentionally separate from `PureYAML` while the chunked input, @@ -43,6 +49,28 @@ try parser.parseDocuments(from: url) { document in } ``` +## WASM Browser Smoke Site + +Live site: + +`https://mihaelamj.github.io/PureYAMLStreaming/` + +Build the Swift WASI smoke executable and copy it into the static test site: + +```sh +bash scripts/build-wasm-site.sh +``` + +Serve the site locally: + +```sh +bash scripts/serve-wasm-site.sh +``` + +Then open `http://localhost:8080` and click **Run WASM Test**. The page loads +`pureyaml-streaming-wasm-smoke.wasm`, runs a chunked document-stream parse in +the browser through a WASI shim, captures stdout, and renders pass/fail. + ## Relationship To PureYAML `PureYAML` remains the dependency-free core package. This package is the diff --git a/Sources/PureYAMLStreamingWasmSmoke/main.swift b/Sources/PureYAMLStreamingWasmSmoke/main.swift new file mode 100644 index 0000000..a8a80fb --- /dev/null +++ b/Sources/PureYAMLStreamingWasmSmoke/main.swift @@ -0,0 +1,76 @@ +import Foundation +import PureYAML +import PureYAMLStreaming + +struct SmokeResult: Encodable { + var ok: Bool + var documentCount: Int + var firstName: String? + var lastName: String? + var message: String +} + +let yaml = Data( + """ + --- + name: browser-0 + enabled: true + nested: + index: 0 + --- + name: browser-1 + enabled: false + nested: + index: 1 + --- + name: browser-2 + enabled: true + nested: + index: 2 + """.utf8, +) + +do { + let parser = PureYAMLStreaming.Parser(chunkSize: 7) + let documents = try parser.collectDocuments(data: yaml) + let names = documents.compactMap { document in + stringValue("name", in: document.value) + } + let ok = documents.count == 3 + && names.first == "browser-0" + && names.last == "browser-2" + let result = SmokeResult( + ok: ok, + documentCount: documents.count, + firstName: names.first, + lastName: names.last, + message: ok ? "PureYAMLStreaming WASM smoke passed" : "PureYAMLStreaming WASM smoke failed", + ) + print(try renderJSON(result)) + Foundation.exit(ok ? 0 : 1) +} catch { + let result = SmokeResult( + ok: false, + documentCount: 0, + firstName: nil, + lastName: nil, + message: String(describing: error), + ) + print((try? renderJSON(result)) ?? #"{"ok":false,"message":"failed to render error"}"#) + Foundation.exit(1) +} + +func stringValue(_ key: String, in value: PureYAML.Model.Value) -> String? { + guard case let .mapping(mapping) = value, + case let .string(string)? = mapping[key] + else { + return nil + } + return string +} + +func renderJSON(_ value: Value) throws -> String { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + return String(decoding: try encoder.encode(value), as: UTF8.self) +} diff --git a/Tests/PureYAMLStreamingTests/StreamingTests.swift b/Tests/PureYAMLStreamingTests/StreamingTests.swift index 18ba49c..7fa5406 100644 --- a/Tests/PureYAMLStreamingTests/StreamingTests.swift +++ b/Tests/PureYAMLStreamingTests/StreamingTests.swift @@ -57,14 +57,7 @@ struct StreamingTests { @Test("streaming matches PureYAML on Geekbench fixtures") func streamingMatchesGeekbenchFixtures() throws { - let fixtureRoot = URL(fileURLWithPath: #filePath) - .deletingLastPathComponent() - .deletingLastPathComponent() - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("PureYAMLGeekbench") - .appendingPathComponent("Fixtures") - .appendingPathComponent("real-yaml") + let fixtureRoot = geekbenchFixtureRoot() guard FileManager.default.fileExists(atPath: fixtureRoot.path) else { return } @@ -78,16 +71,48 @@ struct StreamingTests { #expect(files.count >= 100) - let streamingParser = PureYAMLStreaming.Parser(chunkSize: 4096) + let streamingParser = PureYAMLStreaming.Parser(chunkSize: 31) let pureParser = PureYAML.Parsing.Parser() for file in files { let data = try Data(contentsOf: file) - let streamed = try streamingParser.collectDocuments(data: data).map(\.value) + var streamed: [PureYAML.Model.Value] = [] + try streamingParser.parseDocuments(from: file) { document in + streamed.append(document.value) + } let direct = try pureParser.parseStream(String(decoding: data, as: UTF8.self)).map(\.value) #expect(streamed == direct) } } + @Test("parser streams generated large file without collecting documents") + func parserStreamsGeneratedLargeFileWithoutCollectingDocuments() throws { + let fileURL = FileManager.default.temporaryDirectory + .appendingPathComponent("pureyaml-stream-\(UUID().uuidString).yaml") + try writeGeneratedStream(to: fileURL, documentCount: 5_000) + defer { + try? FileManager.default.removeItem(at: fileURL) + } + + let parser = PureYAMLStreaming.Parser(chunkSize: 37) + var count = 0 + var firstName: String? + var lastName: String? + + try parser.parseDocuments(from: fileURL) { document in + let name = stringValue("name", in: document.value) + if count == 0 { + firstName = name + } + lastName = name + #expect(document.index == count) + count += 1 + } + + #expect(count == 5_000) + #expect(firstName == "doc-0") + #expect(lastName == "doc-4999") + } + private func stringValue(_ key: String, in value: PureYAML.Model.Value) -> String? { guard case let .mapping(mapping) = value, case let .string(string)? = mapping[key] @@ -96,4 +121,39 @@ struct StreamingTests { } return string } + + private func geekbenchFixtureRoot() -> URL { + URL(fileURLWithPath: #filePath) + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + .appendingPathComponent("PureYAMLGeekbench") + .appendingPathComponent("Fixtures") + .appendingPathComponent("real-yaml") + } + + private func writeGeneratedStream(to fileURL: URL, documentCount: Int) throws { + FileManager.default.createFile(atPath: fileURL.path, contents: nil) + let handle = try FileHandle(forWritingTo: fileURL) + defer { + try? handle.close() + } + + for index in 0 ..< documentCount { + let document = """ + --- + name: doc-\(index) + enabled: \(index.isMultiple(of: 2) ? "true" : "false") + nested: + index: \(index) + tags: + - real + - streaming + - chunk-\(index % 17) + + """ + try handle.write(contentsOf: Data(document.utf8)) + } + } } diff --git a/WasmSite/index.html b/WasmSite/index.html new file mode 100644 index 0000000..fb395c1 --- /dev/null +++ b/WasmSite/index.html @@ -0,0 +1,31 @@ + + + + + + PureYAMLStreaming WASM Smoke + + + +
+
+

PureYAMLStreaming

+

WASM Streaming Smoke Test

+

+ This page loads the Swift WASI build in the browser, runs a + document-streaming parse, captures stdout, and reports whether the + smoke test passed. +

+ +
Idle
+
+ +
+

Output

+
Click "Run WASM Test".
+
+
+ + + + diff --git a/WasmSite/main.js b/WasmSite/main.js new file mode 100644 index 0000000..ec9740e --- /dev/null +++ b/WasmSite/main.js @@ -0,0 +1,115 @@ +import { + File, + OpenFile, + WASI, +} from "https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.4.1/+esm"; + +const runButton = document.querySelector("#runButton"); +const statusElement = document.querySelector("#status"); +const outputElement = document.querySelector("#output"); +const params = new URLSearchParams(location.search); +const wasmURL = params.get("wasm") || "./pureyaml-streaming-wasm-smoke.wasm.gz"; + +runButton.addEventListener("click", () => { + runSmokeTest().catch((error) => { + renderFailure(error); + }); +}); + +async function runSmokeTest() { + runButton.disabled = true; + statusElement.className = "status idle"; + statusElement.textContent = "Running..."; + outputElement.textContent = "Loading WASM..."; + + const wasmBytes = await loadWasmBytes(wasmURL); + + const stdout = new CapturingFile(); + const stderr = new CapturingFile(); + const fds = [ + new OpenFile(new File([])), + new OpenFile(stdout), + new OpenFile(stderr), + ]; + const wasi = new WASI([], [], fds); + const wasm = await WebAssembly.compile(wasmBytes); + const instance = await WebAssembly.instantiate(wasm, { + wasi_snapshot_preview1: wasi.wasiImport, + }); + + let exitCode = 0; + try { + wasi.start(instance); + } catch (error) { + if (typeof error?.code === "number") { + exitCode = error.code; + } else { + throw error; + } + } + + const stdoutText = stdout.text(); + const stderrText = stderr.text(); + const parsed = parseSmokeOutput(stdoutText); + const ok = exitCode === 0 && parsed?.ok === true; + + statusElement.className = ok ? "status pass" : "status fail"; + statusElement.textContent = ok ? "Passed" : "Failed"; + outputElement.textContent = [ + `exitCode: ${exitCode}`, + "", + "stdout:", + stdoutText || "(empty)", + "", + "stderr:", + stderrText || "(empty)", + ].join("\n"); + runButton.disabled = false; +} + +async function loadWasmBytes(url) { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch WASM: HTTP ${response.status}`); + } + const bytes = await response.arrayBuffer(); + if (!url.endsWith(".gz")) { + return bytes; + } + if (!("DecompressionStream" in globalThis)) { + throw new Error("This browser does not support DecompressionStream."); + } + const stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream("gzip")); + return new Response(stream).arrayBuffer(); +} + +function parseSmokeOutput(text) { + try { + return JSON.parse(text); + } catch { + return null; + } +} + +function renderFailure(error) { + statusElement.className = "status fail"; + statusElement.textContent = "Failed"; + outputElement.textContent = String(error?.stack || error); + runButton.disabled = false; +} + +class CapturingFile extends File { + constructor() { + super([]); + this.bytes = []; + } + + write(buffer) { + this.bytes.push(...buffer); + return { ret: buffer.length }; + } + + text() { + return new TextDecoder().decode(new Uint8Array(this.bytes)); + } +} diff --git a/WasmSite/style.css b/WasmSite/style.css new file mode 100644 index 0000000..dc2028d --- /dev/null +++ b/WasmSite/style.css @@ -0,0 +1,94 @@ +:root { + color-scheme: light dark; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", + sans-serif; + background: Canvas; + color: CanvasText; +} + +body { + margin: 0; + min-height: 100vh; + display: grid; + place-items: center; +} + +main { + width: min(920px, calc(100vw - 32px)); + display: grid; + gap: 20px; +} + +.card { + border: 1px solid color-mix(in srgb, CanvasText 18%, transparent); + border-radius: 20px; + padding: 28px; + background: color-mix(in srgb, Canvas 92%, CanvasText 8%); + box-shadow: 0 24px 80px color-mix(in srgb, CanvasText 12%, transparent); +} + +.eyebrow { + margin: 0 0 10px; + text-transform: uppercase; + letter-spacing: 0.12em; + font-size: 12px; + opacity: 0.7; +} + +h1, +h2 { + margin: 0 0 12px; + line-height: 1.05; +} + +h1 { + font-size: clamp(36px, 7vw, 72px); +} + +p { + max-width: 720px; + line-height: 1.6; + opacity: 0.82; +} + +button { + appearance: none; + border: 0; + border-radius: 999px; + padding: 12px 18px; + font: inherit; + font-weight: 700; + cursor: pointer; + background: CanvasText; + color: Canvas; +} + +button:disabled { + cursor: wait; + opacity: 0.55; +} + +.status { + margin-top: 18px; + display: inline-flex; + border-radius: 999px; + padding: 8px 12px; + font-weight: 700; + background: color-mix(in srgb, CanvasText 10%, transparent); +} + +.status.pass { + background: color-mix(in srgb, #008a45 30%, transparent); +} + +.status.fail { + background: color-mix(in srgb, #c21f39 30%, transparent); +} + +pre { + margin: 0; + white-space: pre-wrap; + overflow-wrap: anywhere; + line-height: 1.5; +} diff --git a/scripts/build-wasm-site.sh b/scripts/build-wasm-site.sh new file mode 100755 index 0000000..9752f0b --- /dev/null +++ b/scripts/build-wasm-site.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SDK_ID="${PUREYAML_STREAMING_WASM_SDK:-swift-6.3.2-RELEASE_wasm}" +SWIFT_SELECTOR="${PUREYAML_STREAMING_WASM_SWIFT_SELECTOR:-+6.3.2}" +PRODUCT="pureyaml-streaming-wasm-smoke" +SITE_DIR="$ROOT_DIR/WasmSite" + +swift_command() { + if command -v swiftly >/dev/null 2>&1; then + swiftly run swift "$@" "$SWIFT_SELECTOR" + else + swift "$@" + fi +} + +if ! swift_command sdk list | grep -qx "$SDK_ID"; then + echo "wasm: missing Swift SDK '$SDK_ID'" >&2 + echo "wasm: install the SDK or set PUREYAML_STREAMING_WASM_SDK" >&2 + exit 2 +fi + +swift_command build \ + --package-path "$ROOT_DIR" \ + --swift-sdk "$SDK_ID" \ + -c release \ + --product "$PRODUCT" + +BIN_PATH="$(swift_command build \ + --package-path "$ROOT_DIR" \ + --swift-sdk "$SDK_ID" \ + -c release \ + --show-bin-path)" +WASM_PATH="$BIN_PATH/$PRODUCT.wasm" +STAGED_WASM="$SITE_DIR/$PRODUCT.wasm" + +if command -v wasm-opt >/dev/null 2>&1; then + wasm-opt -Oz --strip-debug --strip-producers "$WASM_PATH" -o "$STAGED_WASM" +else + cp "$WASM_PATH" "$STAGED_WASM" +fi + +gzip -9 -c "$STAGED_WASM" > "$STAGED_WASM.gz" + +echo "WASM test site ready:" +echo " $SITE_DIR/index.html" +echo " $STAGED_WASM.gz" +echo +echo "Serve it with:" +echo " bash scripts/serve-wasm-site.sh" diff --git a/scripts/serve-wasm-site.sh b/scripts/serve-wasm-site.sh new file mode 100755 index 0000000..50168cb --- /dev/null +++ b/scripts/serve-wasm-site.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PORT="${1:-8080}" + +cd "$ROOT_DIR/WasmSite" +python3 -m http.server "$PORT"