From f591be4636db480fa616f6e8bd27f10fc2ae74c2 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 31 Mar 2025 10:46:56 +0900 Subject: [PATCH 1/4] docs: Add a guide on deploying with Vite --- .../Articles/Deploying-Pages.md | 97 +++++++++++++++++++ .../Hello-World/Hello-World.tutorial | 2 +- .../Resources/hello-world-3-2-server.txt | 3 +- .../Resources/hello-world-3-3-open.txt | 5 +- 4 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 Sources/JavaScriptKit/Documentation.docc/Articles/Deploying-Pages.md diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/Deploying-Pages.md b/Sources/JavaScriptKit/Documentation.docc/Articles/Deploying-Pages.md new file mode 100644 index 000000000..96789f206 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/Deploying-Pages.md @@ -0,0 +1,97 @@ +# Deploying Pages + +Deploy your applications built with JavaScriptKit to the web. + +## Overview + +Once you've built your application with JavaScriptKit, you'll need to deploy it to make it accessible on the web. This guide covers the deployment process, including building your application and deploying it to various hosting platforms. + +## Building Your Application with Vite + +Build your application using [Vite](https://vite.dev/) build tool: + +```bash +# Build the Swift package for WebAssembly +$ swift package --swift-sdk wasm32-unknown-wasi js -c release + +# Create a minimal HTML file (if you don't have one) +$ cat < index.html + + + + + + +EOS + +# Install Vite and add the WebAssembly output as a dependency +$ npm install -D vite .build/plugins/PackageToJS/outputs/Package + +# Build optimized assets +$ npx vite build +``` + +This will generate optimized static assets in the `dist` directory, ready for deployment. + +## Deployment Options + +### GitHub Pages + +1. Set up your repository for GitHub Pages in your repository settings and select "GitHub Actions" as source. +2. Create a GitHub Actions workflow to build and deploy your application: + +```yaml +name: Deploy to GitHub Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: [main] + +# Sets the GITHUB_TOKEN permissions to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + container: swift:6.0.3 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: actions/configure-pages@v4 + id: pages + # Install Swift SDK for WebAssembly + - uses: swiftwasm/setup-swiftwasm@v2 + - name: Build + run: | + swift package --swift-sdk wasm32-unknown-wasi js -c release + npm install + npx vite build --base "${{ steps.pages.outputs.base_path }}" + - uses: actions/upload-pages-artifact@v3 + with: + path: './dist' + - uses: actions/deploy-pages@v4 + id: deployment +``` + +## Cross-Origin Isolation Requirements + +When using `wasm32-unknown-wasip1-threads` target, you must enable [Cross-Origin Isolation](https://developer.mozilla.org/en-US/docs/Web/API/Window/crossOriginIsolated) by setting the following HTTP headers: + +``` +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin +``` + +These headers are required for SharedArrayBuffer support, which is used by the threading implementation. diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Hello-World.tutorial b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Hello-World.tutorial index f5ede8f19..c054e3a48 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Hello-World.tutorial +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Hello-World.tutorial @@ -84,7 +84,7 @@ @Step { Start a local web server to serve your application: This starts a simple HTTP server that serves files from your current directory. - + > Note: If you are building your app with `wasm32-unknown-wasip1-threads` target, you need to enable [Cross-Origin Isolation](https://developer.mozilla.org/en-US/docs/Web/API/Window/crossOriginIsolated) for `SharedArrayBuffer`. See "Cross-Origin Isolation Requirements" in @Code(name: "Console", file: "hello-world-3-2-server.txt") } diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-2-server.txt b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-2-server.txt index 569396481..ad560a635 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-2-server.txt +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-2-server.txt @@ -4,5 +4,4 @@ Build of product 'Hello' complete! (5.16s) Packaging... ... Packaging finished -$ python3 -m http.server -Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... +$ npx serve diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-open.txt b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-open.txt index f4df8ec2f..8abe30b7c 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-open.txt +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-open.txt @@ -4,6 +4,5 @@ Build of product 'Hello' complete! (5.16s) Packaging... ... Packaging finished -$ python3 -m http.server -Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... -$ open http://localhost:8000 +$ npx serve +$ open http://localhost:3000 From fccfd971c3c5f4b8f82713e4327d9de4ee120684 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 31 Mar 2025 22:43:41 +0000 Subject: [PATCH 2/4] Fix node version diagnostic handling on test harness The CompileError usually happens during `defaultNodeSetup`, so we should catch it there. Also `process.version` is a string with a `v` prefix, so we should use `process.versions.node`, which doesn't have the prefix instead. --- Plugins/PackageToJS/Templates/bin/test.js | 46 +++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Plugins/PackageToJS/Templates/bin/test.js b/Plugins/PackageToJS/Templates/bin/test.js index b31d82086..f888b9d1c 100644 --- a/Plugins/PackageToJS/Templates/bin/test.js +++ b/Plugins/PackageToJS/Templates/bin/test.js @@ -38,35 +38,35 @@ const args = parseArgs({ const harnesses = { node: async ({ preludeScript }) => { - let options = await nodePlatform.defaultNodeSetup({ - args: testFrameworkArgs, - onExit: (code) => { - if (code !== 0) { return } - // Extract the coverage file from the wasm module - const filePath = "default.profraw" - const destinationPath = args.values["coverage-file"] ?? filePath - const profraw = options.wasi.extractFile?.(filePath) - if (profraw) { - console.log(`Saved ${filePath} to ${destinationPath}`); - writeFileSync(destinationPath, profraw); + try { + let options = await nodePlatform.defaultNodeSetup({ + args: testFrameworkArgs, + onExit: (code) => { + if (code !== 0) { return } + // Extract the coverage file from the wasm module + const filePath = "default.profraw" + const destinationPath = args.values["coverage-file"] ?? filePath + const profraw = options.wasi.extractFile?.(filePath) + if (profraw) { + console.log(`Saved ${filePath} to ${destinationPath}`); + writeFileSync(destinationPath, profraw); + } + }, + /* #if USE_SHARED_MEMORY */ + spawnWorker: nodePlatform.createDefaultWorkerFactory(preludeScript) + /* #endif */ + }) + if (preludeScript) { + const prelude = await import(preludeScript) + if (prelude.setupOptions) { + options = prelude.setupOptions(options, { isMainThread: true }) } - }, - /* #if USE_SHARED_MEMORY */ - spawnWorker: nodePlatform.createDefaultWorkerFactory(preludeScript) - /* #endif */ - }) - if (preludeScript) { - const prelude = await import(preludeScript) - if (prelude.setupOptions) { - options = prelude.setupOptions(options, { isMainThread: true }) } - } - try { await instantiate(options) } catch (e) { if (e instanceof WebAssembly.CompileError) { // Check Node.js major version - const nodeVersion = process.version.split(".")[0] + const nodeVersion = process.versions.node.split(".")[0] const minNodeVersion = 20 if (nodeVersion < minNodeVersion) { console.error(`Hint: Node.js version ${nodeVersion} is not supported, please use version ${minNodeVersion} or later.`) From c80eed35c2f838c7fcc258ccab682f52000ebcb5 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 1 Apr 2025 13:46:53 +0000 Subject: [PATCH 3/4] build: Fix native build for missing symbol ``` $s13JavaScriptKit8JSObjectC2idACs6UInt32V_tcfc: error: undefined reference to 'swjs_get_worker_thread_id_cached' ``` --- Sources/_CJavaScriptKit/_CJavaScriptKit.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/_CJavaScriptKit/_CJavaScriptKit.c b/Sources/_CJavaScriptKit/_CJavaScriptKit.c index ed8240ca1..a32881804 100644 --- a/Sources/_CJavaScriptKit/_CJavaScriptKit.c +++ b/Sources/_CJavaScriptKit/_CJavaScriptKit.c @@ -1,18 +1,18 @@ #include "_CJavaScriptKit.h" #if __wasm32__ -#ifndef __wasi__ -#if __has_include("malloc.h") -#include -#endif +# ifndef __wasi__ +# if __has_include("malloc.h") +# include +# endif extern void *malloc(size_t size); extern void free(void *ptr); extern void *memset (void *, int, size_t); extern void *memcpy (void *__restrict, const void *__restrict, size_t); -#else -#include -#include +# else +# include +# include -#endif +# endif /// The compatibility runtime library version. /// Notes: If you change any interface of runtime library, please increment /// this and `SwiftRuntime.version` in `./Runtime/src/index.ts`. @@ -34,7 +34,7 @@ void swjs_cleanup_host_function_call(void *argv_buffer) { // NOTE: This __wasi__ check is a hack for Embedded compatibility (assuming that if __wasi__ is defined, we are not building for Embedded) // cdecls don't work in Embedded, but @_expose(wasm) can be used with Swift >=6.0 // the previously used `#if __Embedded` did not play well with SwiftPM (defines needed to be on every target up the chain) -#ifdef __wasi__ +# ifdef __wasi__ bool _call_host_function_impl(const JavaScriptHostFuncRef host_func_ref, const RawJSValue *argv, const int argc, const JavaScriptObjectRef callback_func); @@ -59,6 +59,8 @@ __attribute__((export_name("swjs_library_features"))) int swjs_library_features(void) { return _library_features(); } +# endif +#endif int swjs_get_worker_thread_id_cached(void) { _Thread_local static int tid = 0; @@ -67,5 +69,3 @@ int swjs_get_worker_thread_id_cached(void) { } return tid; } -#endif -#endif From 4709005e1b82b8112f5e2b5da4e15bbc0467d0ec Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 1 Apr 2025 13:48:29 +0000 Subject: [PATCH 4/4] CI: Ensure that linking works correctly for native targets --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 174b873ef..35405eaf6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,7 +64,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - run: swift build + - run: swift build --package-path ./Examples/Basic env: DEVELOPER_DIR: /Applications/${{ matrix.xcode }}.app/Contents/Developer/