用于通过 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!")
从 SwiftWasm 5.5 开始,您可以将 async
/await
与 JSPromise
对象一起使用。但这需要一些额外的步骤(如果您的应用程序依赖于 Tokamak,则可以跳过这些步骤)
Packages.swift
中依赖于 JavaScriptEventLoop
.target(
name: "JavaScriptKitExample",
dependencies: [
"JavaScriptKit",
.product(name: "JavaScriptEventLoop", package: "JavaScriptKit"),
]
)
await
和/或 Task
API *之前* 执行的代码中添加显式导入(最有可能在 main.swift
中)import JavaScriptEventLoop
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 套件中执行可以由 JS 事件循环恢复的 Swift 异步函数,请将 JavaScriptEventLoopTestSupport
添加到您的测试 target 依赖项中。
.testTarget(
name: "MyAppTests",
dependencies: [
"MyApp",
+ "JavaScriptEventLoopTestSupport",
]
)
链接此模块会自动通过调用 JavaScriptEventLoop.installGlobalExecutor()
来激活基于 JS 事件循环的全局执行器
Package.swift
清单中添加 .unsafeFlags(["-Xfrontend", "-disable-availability-checking"])
。您也可以在 macOS Monterey 上使用 Xcode 13.0 和 13.1,因为此操作系统不需要向后部署。任何最新的浏览器,只要它支持 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
警告
carton
,则可以使用 brew uninstall carton
卸载它,并将新版本作为 SwiftPM 依赖项安装。carton
之前删除旧的 .build
目录作为这些步骤的一部分,您将在 macOS 上通过 Homebrew 安装 carton
(如果您希望在 Linux 上运行构建步骤,也可以使用 ghcr.io/swiftwasm/carton
Docker 镜像)。假设您已经安装了 Homebrew,您可以按照以下步骤创建一个使用 JavaScriptKit 的新应用程序
carton
brew install swiftwasm/tap/carton
如果您之前安装过 carton
,请确保您的版本为 0.6.1 或更高版本
carton --version
mkdir SwiftWasmApp && cd SwiftWasmApp
carton
从模板初始化项目carton init --template basic
carton dev
可以在开发期间保持运行carton dev
在浏览器中打开 http://127.0.0.1:8080/ 以及其中的开发者控制台。您将在控制台中看到 Hello, world!
输出。您可以在您喜欢的编辑器中编辑应用程序源代码并保存,carton
将立即重建应用程序并重新加载所有打开了该应用程序的浏览器标签。
您还可以使用 webpack.js 和手动安装的 SwiftWasm 工具链构建您的项目。有关此更高级用例的更多信息,请参阅以下部分和 Example 目录。
成为黄金或白金赞助商 并联系维护者,将您的徽标添加到我们在 Github 上的 README 中,并附上指向您网站的链接。