diff --git a/.gitignore b/.gitignore index 1d3cb87be..2fb37cb48 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ xcuserdata/ .vscode Examples/*/Bundle Examples/*/package-lock.json +/Package.resolved diff --git a/Package.swift b/Package.swift index 7c49f0e33..173add2dd 100644 --- a/Package.swift +++ b/Package.swift @@ -83,3 +83,9 @@ let package = Package( ), ] ) + +if Context.environment["JAVASCRIPTKIT_USE_DOCC_PLUGIN"] != nil { + package.dependencies.append( + .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.4.0") + ) +} diff --git a/README.md b/README.md index e7a9b63a5..c03561587 100644 --- a/README.md +++ b/README.md @@ -4,262 +4,51 @@ Swift framework to interact with JavaScript through WebAssembly. -## Getting started +## Quick Start -This JavaScript code +Check out the [Hello World](https://swiftpackageindex.com/swiftwasm/JavaScriptKit/main/tutorials/javascriptkit/hello-world) tutorial for a step-by-step guide to getting started. -```javascript -const alert = window.alert; -const document = window.document; +## Overview -const divElement = document.createElement("div"); -divElement.innerText = "Hello, world"; -const body = document.body; -body.appendChild(divElement); +JavaScriptKit provides a seamless way to interact with JavaScript from Swift code when compiled to WebAssembly. It allows Swift developers to: -const pet = { - age: 3, - owner: { - name: "Mike", - }, -}; - -alert("JavaScript is running on browser!"); -``` - -Can be written in Swift using JavaScriptKit +- Access JavaScript objects and functions +- Create closures that can be called from JavaScript +- Convert between Swift and JavaScript data types +- Use JavaScript promises with Swift's `async/await` +- Work with multi-threading ```swift import JavaScriptKit +// Access global JavaScript objects let document = JSObject.global.document -var divElement = document.createElement("div") -divElement.innerText = "Hello, world" -_ = document.body.appendChild(divElement) - -struct Owner: Codable { - let name: String -} - -struct Pet: Codable { - let age: Int - let owner: Owner -} - -let jsPet = JSObject.global.pet -let swiftPet: Pet = try JSValueDecoder().decode(from: jsPet) - -_ = JSObject.global.alert!("Swift is running in the browser!") -``` - -### `async`/`await` - -Starting with SwiftWasm 5.5 you can use `async`/`await` with `JSPromise` objects. This requires -a few additional steps though (you can skip these steps if your app depends on -[Tokamak](https://tokamak.dev)): - -1. Make sure that your target depends on `JavaScriptEventLoop` in your `Packages.swift`: - -```swift -.target( - name: "JavaScriptKitExample", - dependencies: [ - "JavaScriptKit", - .product(name: "JavaScriptEventLoop", package: "JavaScriptKit"), - ] -) -``` - -2. Add an explicit import in the code that executes **before* you start using `await` and/or `Task` -APIs (most likely in `main.swift`): - -```swift -import JavaScriptEventLoop -``` - -3. Run this function **before* you start using `await` and/or `Task` APIs (again, most likely in -`main.swift`): - -```swift -JavaScriptEventLoop.installGlobalExecutor() -``` - -Then you can `await` on the `value` property of `JSPromise` instances, like in the example below: - -```swift -import JavaScriptKit -import JavaScriptEventLoop - -let alert = JSObject.global.alert.function! -let document = JSObject.global.document - -private let jsFetch = JSObject.global.fetch.function! -func fetch(_ url: String) -> JSPromise { - JSPromise(jsFetch(url).object!)! -} - -JavaScriptEventLoop.installGlobalExecutor() - -struct Response: Decodable { - let uuid: String -} - -var asyncButtonElement = document.createElement("button") -asyncButtonElement.innerText = "Fetch UUID demo" -asyncButtonElement.onclick = .object(JSClosure { _ in - Task { - do { - let response = try await fetch("https://httpbin.org/uuid").value - let json = try await JSPromise(response.json().object!)!.value - let parsedResponse = try JSValueDecoder().decode(Response.self, from: json) - alert(parsedResponse.uuid) - } catch { - print(error) - } - } +// Create and manipulate DOM elements +var div = document.createElement("div") +div.innerText = "Hello from Swift!" +_ = document.body.appendChild(div) +// Handle events with Swift closures +var button = document.createElement("button") +button.innerText = "Click me" +button.onclick = .object(JSClosure { _ in + JSObject.global.alert!("Button clicked!") return .undefined }) - -_ = document.body.appendChild(asyncButtonElement) -``` - -### `JavaScriptEventLoop` activation in XCTest suites - -If you need to execute Swift async functions that can be resumed by JS event loop in your XCTest suites, please add `JavaScriptEventLoopTestSupport` to your test target dependencies. - -```diff - .testTarget( - name: "MyAppTests", - dependencies: [ - "MyApp", -+ "JavaScriptEventLoopTestSupport", - ] - ) -``` - -Linking this module automatically activates JS event loop based global executor by calling `JavaScriptEventLoop.installGlobalExecutor()` - - -## Requirements - -### For developers - -- macOS 11 and Xcode 13.2 or later versions, which support Swift Concurrency back-deployment. -To use earlier versions of Xcode on macOS 11 you'll have to -add `.unsafeFlags(["-Xfrontend", "-disable-availability-checking"])` in `Package.swift` manifest of -your package that depends on JavaScriptKit. You can also use Xcode 13.0 and 13.1 on macOS Monterey, -since this OS does not need back-deployment. -- [Swift 5.5 or later](https://swift.org/download/) and Ubuntu 18.04 if you'd like to use Linux. - Other Linux distributions are currently not supported. - -### For users of apps depending on JavaScriptKit - -Any recent browser that [supports WebAssembly](https://caniuse.com/#feat=wasm) and required -JavaScript features should work, which currently includes: - -- Edge 84+ -- Firefox 79+ -- Chrome 84+ -- Desktop Safari 14.1+ -- Mobile Safari 14.8+ - -If you need to support older browser versions, you'll have to build with -the `JAVASCRIPTKIT_WITHOUT_WEAKREFS` flag, passing `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS` flags -when compiling. This should lower browser requirements to these versions: - -- Edge 16+ -- Firefox 61+ -- Chrome 66+ -- (Mobile) Safari 12+ - -Not all of these versions are tested on regular basis though, compatibility reports are very welcome! - -## Usage in a browser application - -The easiest is to start with [Examples](/Examples) which has JavaScript glue runtime. - -Second option is to get started with JavaScriptKit in your browser app is with [the `carton` -bundler](https://carton.dev). Add carton to your swift package dependencies: - -```diff -dependencies: [ -+ .package(url: "https://github.com/swiftwasm/carton", from: "1.1.3"), -], -``` - -Now you can activate the package dependency through swift: - -``` -swift run carton dev +_ = document.body.appendChild(button) ``` -If you have multiple products in your package, you can also used the product flag: - -``` -swift run carton dev --product MyApp -``` +Check out the [examples](https://github.com/swiftwasm/JavaScriptKit/tree/main/Examples) for more detailed usage. -> [!WARNING] -> - If you already use `carton` before 0.x.x versions via Homebrew, you can remove it with `brew uninstall carton` and install the new version as a SwiftPM dependency. -> - Also please remove the old `.build` directory before using the new `carton` +## Contributing -
Legacy Installation - ---- - -As a part of these steps -you'll install `carton` via [Homebrew](https://brew.sh/) on macOS (you can also use the -[`ghcr.io/swiftwasm/carton`](https://github.com/orgs/swiftwasm/packages/container/package/carton) -Docker image if you prefer to run the build steps on Linux). Assuming you already have Homebrew -installed, you can create a new app that uses JavaScriptKit by following these steps: - -1. Install `carton`: - -``` -brew install swiftwasm/tap/carton -``` - -If you had `carton` installed before this, make sure you have version 0.6.1 or greater: - -``` -carton --version -``` - -2. Create a directory for your project and make it current: - -``` -mkdir SwiftWasmApp && cd SwiftWasmApp -``` - -3. Initialize the project from a template with `carton`: - -``` -carton init --template basic -``` - -4. Build the project and start the development server, `carton dev` can be kept running - during development: - -``` -carton dev -``` - ---- - -
- -Open [http://127.0.0.1:8080/](http://127.0.0.1:8080/) in your browser and a developer console -within it. You'll see `Hello, world!` output in the console. You can edit the app source code in -your favorite editor and save it, `carton` will immediately rebuild the app and reload all -browser tabs that have the app open. +Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to the project. ## Sponsoring [Become a gold or platinum sponsor](https://github.com/sponsors/swiftwasm/) and contact maintainers to add your logo on our README on Github with a link to your site. - diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/JavaScript-Environment-Requirements.md b/Sources/JavaScriptKit/Documentation.docc/Articles/JavaScript-Environment-Requirements.md new file mode 100644 index 000000000..6483e4ca6 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/JavaScript-Environment-Requirements.md @@ -0,0 +1,48 @@ +# JavaScript Environment Requirements + +## Required JavaScript Features + +The JavaScript package produced by the JavaScriptKit packaging plugin requires the following JavaScript features: + +- [`FinalizationRegistry`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry#browser_compatibility) +- [WebAssembly BigInt to i64 conversion in JS API](https://caniuse.com/wasm-bigint) + +## Browser Compatibility + +These JavaScript features are supported in the following browsers: + +- Chrome 85+ (August 2020) +- Firefox 79+ (July 2020) +- Desktop Safari 14.1+ (April 2021) +- Mobile Safari 14.5+ (April 2021) +- Edge 85+ (August 2020) +- Node.js 15.0+ (October 2020) + +Older browsers will not be able to run applications built with JavaScriptKit unless polyfills are provided. + +## Handling Missing Features + +### FinalizationRegistry + +When using JavaScriptKit in environments without `FinalizationRegistry` support, you can: + +1. Build with the opt-out flag: `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS` +2. Then manually manage memory by calling `release()` on all `JSClosure` instances: + +```swift +let closure = JSClosure { args in + // Your code here + return .undefined +} + +// Use the closure... + +// Then release it when done +#if JAVASCRIPTKIT_WITHOUT_WEAKREFS +closure.release() +#endif +``` + +### WebAssembly BigInt Support + +If you need to work with 64-bit integers in JavaScript, ensure your target environment supports WebAssembly BigInt conversions. For environments that don't support this feature, you'll need to avoid importing `JavaScriptBigIntSupport` diff --git a/Sources/JavaScriptKit/Documentation.docc/Documentation.md b/Sources/JavaScriptKit/Documentation.docc/Documentation.md new file mode 100644 index 000000000..94d5ba3c5 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Documentation.md @@ -0,0 +1,56 @@ +# ``JavaScriptKit`` + +Swift framework to interact with JavaScript through WebAssembly. + +## Overview + +**JavaScriptKit** provides a seamless way to interact with JavaScript from Swift code when compiled to WebAssembly. + +## Quick Start + +Check out the tutorial for a step-by-step guide to getting started. + +### Key Features + +- Access JavaScript objects and functions +- Create closures that can be called from JavaScript +- Convert between Swift and JavaScript data types +- Use JavaScript promises with Swift's `async/await` +- Work with multi-threading + +### Example + +```swift +import JavaScriptKit + +// Access global JavaScript objects +let document = JSObject.global.document + +// Create and manipulate DOM elements +var div = document.createElement("div") +div.innerText = "Hello from Swift!" +_ = document.body.appendChild(div) + +// Handle events with Swift closures +var button = document.createElement("button") +button.innerText = "Click me" +button.onclick = .object(JSClosure { _ in + JSObject.global.alert!("Button clicked!") + return .undefined +}) +_ = document.body.appendChild(button) +``` + +Check out the [examples](https://github.com/swiftwasm/JavaScriptKit/tree/main/Examples) for more detailed usage. + +## Topics + +### Tutorials + +- + +### Core Types + +- +- +- diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Hello-World.tutorial b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Hello-World.tutorial new file mode 100644 index 000000000..f5ede8f19 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Hello-World.tutorial @@ -0,0 +1,101 @@ +@Tutorial(time: 5) { + @Intro(title: "Quick Start: Hello World") { + This tutorial walks you through creating a simple web application using JavaScriptKit. You'll learn how to set up a Swift package, add JavaScriptKit as a dependency, write code to manipulate the DOM, and build and run your web application. + + JavaScriptKit allows you to interact with JavaScript APIs directly from Swift code when targeting WebAssembly, making it easy to build web applications using Swift. + } + + @Section(title: "Prerequisites") { + Visit the [installation guide](https://book.swiftwasm.org/getting-started/setup.html) to install the Swift SDK for WebAssembly before starting this tutorial. + This tutorial assumes you have the Swift SDK for WebAssembly installed. Please check your Swift installation. + + @Steps { + @Step { + Check your Swift toolchain version. If you see different + @Code(name: "Console", file: "hello-world-0-1-swift-version.txt") + } + @Step { + Select a Swift SDK for WebAssembly version that matches the version of the Swift toolchain you have installed. + + The following sections of this tutorial assume you have set the `SWIFT_SDK_ID` environment variable. + @Code(name: "Console", file: "hello-world-0-2-select-sdk.txt") + } + } + } + + @Section(title: "Set up your project") { + Let's start by creating a new Swift package and configuring it to use JavaScriptKit. + + @Steps { + @Step { + Create a new Swift package by running the following command in your terminal: + This creates a new Swift executable package named "Hello" with a basic folder structure. + + @Code(name: "Console", file: "hello-world-1-1-init-package.txt") + } + + @Step { + Add JavaScriptKit as a dependency using the Swift Package Manager: + This command adds the JavaScriptKit GitHub repository as a dependency to your package. + + @Code(name: "Console", file: "hello-world-1-2-add-dependency.txt") + } + + @Step { + Add JavaScriptKit as a target dependency: + This command adds JavaScriptKit as a target dependency to your package. + + @Code(name: "Console", file: "hello-world-1-3-add-target-dependency.txt") + } + } + } + + @Section(title: "Write your web application") { + Now let's write some Swift code that manipulates the DOM to create a simple web page. + + @Steps { + @Step { + Create or modify the main.swift file in your Sources/Hello directory: + This code creates a new div element, sets its text content to "Hello from Swift!", and appends it to the document body. + + @Code(name: "main.swift", file: "hello-world-2-1-main-swift.swift") + } + + @Step { + Create an index.html file in the root of your project to load your WebAssembly application: + This HTML file includes a script that loads and runs your compiled WebAssembly code. + + @Code(name: "index.html", file: "hello-world-2-2-index-html.html") + } + } + } + + @Section(title: "Build and run your application") { + Let's build your application and run it in a web browser. + + @Steps { + @Step { + Build your application with the Swift WebAssembly toolchain: + This command compiles your Swift code to WebAssembly and generates the necessary JavaScript bindings. + + @Code(name: "Console", file: "hello-world-3-1-build.txt") + } + + @Step { + Start a local web server to serve your application: + This starts a simple HTTP server that serves files from your current directory. + + @Code(name: "Console", file: "hello-world-3-2-server.txt") + } + + @Step { + Open your application in a web browser: + Your browser should open and display a page with "Hello from Swift!" as text added by your Swift code. + + @Code(name: "Console", file: "hello-world-3-3-open.txt") { + @Image(alt: "Preview of the web application", source: "hello-world-3-3-app.png") + } + } + } + } +} diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-0-1-swift-version.txt b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-0-1-swift-version.txt new file mode 100644 index 000000000..5d5ad28df --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-0-1-swift-version.txt @@ -0,0 +1,7 @@ +$ swift --version +Apple Swift version 6.0.3 (swift-6.0.3-RELEASE) +or +Swift version 6.0.3 (swift-6.0.3-RELEASE) + +$ swift sdk list +6.0.3-RELEASE-wasm32-unknown-wasi diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-0-2-select-sdk.txt b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-0-2-select-sdk.txt new file mode 100644 index 000000000..b5fc2c620 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-0-2-select-sdk.txt @@ -0,0 +1,9 @@ +$ swift --version +Apple Swift version 6.0.3 (swift-6.0.3-RELEASE) +or +Swift version 6.0.3 (swift-6.0.3-RELEASE) + +$ swift sdk list +6.0.3-RELEASE-wasm32-unknown-wasi + +$ export SWIFT_SDK_ID=6.0.3-RELEASE-wasm32-unknown-wasi diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-1-init-package.txt b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-1-init-package.txt new file mode 100644 index 000000000..938b88e01 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-1-init-package.txt @@ -0,0 +1,6 @@ +$ swift package init --name Hello --type executable +Creating executable package: Hello +Creating Package.swift +Creating .gitignore +Creating Sources/ +Creating Sources/main.swift diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-2-add-dependency.txt b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-2-add-dependency.txt new file mode 100644 index 000000000..358629d0c --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-2-add-dependency.txt @@ -0,0 +1,9 @@ +$ swift package init --name Hello --type executable +Creating executable package: Hello +Creating Package.swift +Creating .gitignore +Creating Sources/ +Creating Sources/main.swift + +$ swift package add-dependency https://github.com/swiftwasm/JavaScriptKit.git --branch main +Updating package manifest at Package.swift... done. diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-3-add-target-dependency.txt b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-3-add-target-dependency.txt new file mode 100644 index 000000000..317690412 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-3-add-target-dependency.txt @@ -0,0 +1,12 @@ +$ swift package init --name Hello --type executable +Creating executable package: Hello +Creating Package.swift +Creating .gitignore +Creating Sources/ +Creating Sources/main.swift + +$ swift package add-dependency https://github.com/swiftwasm/JavaScriptKit.git --branch main +Updating package manifest at Package.swift... done. + +$ swift package add-target-dependency --package JavaScriptKit JavaScriptKit Hello +Updating package manifest at Package.swift... done. diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-2-1-main-swift.swift b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-2-1-main-swift.swift new file mode 100644 index 000000000..156ac0540 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-2-1-main-swift.swift @@ -0,0 +1,6 @@ +import JavaScriptKit + +let document = JSObject.global.document +var div = document.createElement("div") +div.innerText = "Hello from Swift!" +document.body.appendChild(div) diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-2-2-index-html.html b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-2-2-index-html.html new file mode 100644 index 000000000..84a3aa15e --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-2-2-index-html.html @@ -0,0 +1,14 @@ + + + + + Swift Web App + + + +

My Swift Web App

+ + diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-1-build.txt b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-1-build.txt new file mode 100644 index 000000000..9c0ef39c2 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-1-build.txt @@ -0,0 +1,6 @@ +$ swift package --swift-sdk $SWIFT_SDK_ID js --use-cdn +[37/37] Linking Hello.wasm +Build of product 'Hello' complete! (5.16s) +Packaging... +... +Packaging finished 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 new file mode 100644 index 000000000..569396481 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-2-server.txt @@ -0,0 +1,8 @@ +$ swift package --swift-sdk $SWIFT_SDK_ID js --use-cdn +[37/37] Linking Hello.wasm +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/) ... diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-app.png b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-app.png new file mode 100644 index 000000000..033cafbcd Binary files /dev/null and b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-app.png differ 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 new file mode 100644 index 000000000..f4df8ec2f --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-open.txt @@ -0,0 +1,9 @@ +$ swift package --swift-sdk $SWIFT_SDK_ID js --use-cdn +[37/37] Linking Hello.wasm +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 diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Resources/image.png b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Resources/image.png new file mode 100644 index 000000000..5b24016a9 Binary files /dev/null and b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Resources/image.png differ diff --git a/Sources/JavaScriptKit/Documentation.docc/Tutorials/Table-of-Contents.tutorial b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Table-of-Contents.tutorial new file mode 100644 index 000000000..c2950be1e --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Tutorials/Table-of-Contents.tutorial @@ -0,0 +1,9 @@ +@Tutorials(name: "JavaScriptKit") { + @Intro(title: "Working with JavaScriptKit") { + JavaScriptKit is a Swift package that allows you to interact with JavaScript APIs directly from Swift code when targeting WebAssembly. + } + @Chapter(name: "Hello World") { + @Image(source: "image.png") + @TutorialReference(tutorial: "doc:Hello-World") + } +}