JavaScriptKit

Run unit tests

用于通过 WebAssembly 与 JavaScript 交互的 Swift 框架。

开始使用

这段 JavaScript 代码

const alert = window.alert;
const document = window.document;

const divElement = document.createElement("div");
divElement.innerText = "Hello, world";
const body = document.body;
body.appendChild(divElement);

const pet = {
  age: 3,
  owner: {
    name: "Mike",
  },
};

alert("JavaScript is running on browser!");

可以使用 JavaScriptKit 以 Swift 编写

import JavaScriptKit

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

从 SwiftWasm 5.5 开始,您可以将 async/awaitJSPromise 对象一起使用。但这需要一些额外的步骤(如果您的应用程序依赖于 Tokamak,则可以跳过这些步骤)

  1. 确保您的 target 在 Packages.swift 中依赖于 JavaScriptEventLoop
.target(
    name: "JavaScriptKitExample",
    dependencies: [
        "JavaScriptKit",
        .product(name: "JavaScriptEventLoop", package: "JavaScriptKit"),
    ]
)
  1. 在使用 await 和/或 Task API *之前* 执行的代码中添加显式导入(最有可能在 main.swift 中)
import JavaScriptEventLoop
  1. 在您开始使用 await 和/或 Task API *之前* 运行此函数(同样,最有可能在 main.swift 中)
JavaScriptEventLoop.installGlobalExecutor()

然后您可以在 JSPromise 实例的 value 属性上使用 await,如下例所示

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)
        }
    }

    return .undefined
})

_ = document.body.appendChild(asyncButtonElement)

XCTest 套件中的 JavaScriptEventLoop 激活

如果您需要在 XCTest 套件中执行可以由 JS 事件循环恢复的 Swift 异步函数,请将 JavaScriptEventLoopTestSupport 添加到您的测试 target 依赖项中。

 .testTarget(
   name: "MyAppTests",
   dependencies: [
     "MyApp",
+    "JavaScriptEventLoopTestSupport",
   ]
 )

链接此模块会自动通过调用 JavaScriptEventLoop.installGlobalExecutor() 来激活基于 JS 事件循环的全局执行器

要求

对于开发者

对于依赖 JavaScriptKit 的应用程序用户

任何最新的浏览器,只要它支持 WebAssembly 并且具有所需的 JavaScript 功能即可,目前包括

如果您需要支持旧版本的浏览器,则必须使用 JAVASCRIPTKIT_WITHOUT_WEAKREFS 标志进行构建,并在编译时传递 -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS 标志。 这应该会将浏览器要求降低到以下版本

尽管并非所有这些版本都经过定期测试,但非常欢迎兼容性报告!

在浏览器应用程序中使用

在浏览器应用程序中开始使用 JavaScriptKit 最简单的方法是使用 carton 打包器。将 carton 添加到您的 swift 软件包依赖项中

dependencies: [
+    .package(url: "https://github.com/swiftwasm/carton", from: "1.0.0"),
],

现在您可以通过 swift 激活软件包依赖项

swift run carton dev

如果您的软件包中有多个产品,您也可以使用 product 标志

swift run carton dev --product MyApp

警告

旧版安装

作为这些步骤的一部分,您将在 macOS 上通过 Homebrew 安装 carton(如果您希望在 Linux 上运行构建步骤,也可以使用 ghcr.io/swiftwasm/carton Docker 镜像)。假设您已经安装了 Homebrew,您可以按照以下步骤创建一个使用 JavaScriptKit 的新应用程序

  1. 安装 carton
brew install swiftwasm/tap/carton

如果您之前安装过 carton,请确保您的版本为 0.6.1 或更高版本

carton --version
  1. 为您的项目创建一个目录并将其设为当前目录
mkdir SwiftWasmApp && cd SwiftWasmApp
  1. 使用 carton 从模板初始化项目
carton init --template basic
  1. 构建项目并启动开发服务器,carton dev 可以在开发期间保持运行
carton dev

在浏览器中打开 http://127.0.0.1:8080/ 以及其中的开发者控制台。您将在控制台中看到 Hello, world! 输出。您可以在您喜欢的编辑器中编辑应用程序源代码并保存,carton 将立即重建应用程序并重新加载所有打开了该应用程序的浏览器标签。

您还可以使用 webpack.js 和手动安装的 SwiftWasm 工具链构建您的项目。有关此更高级用例的更多信息,请参阅以下部分和 Example 目录。

赞助

成为黄金或白金赞助商 并联系维护者,将您的徽标添加到我们在 Github 上的 README 中,并附上指向您网站的链接。