SwiftWasm 5.9.1 is now available
SwiftWasm 5.9.1 has been released.
We're happy to announce the new release of SwiftWasm tracking upstream Swift 5.9.1!
This is a periodic release of SwiftWasm, which tracks the upstream Swift 5.9.1 release. As for changes in upstream Swift 5.9, we recommend referring to the official changelog.
For more information about SwiftWasm in general and for getting started, please visit the project documentation. If you have any questions, please come and talk to us on the SwiftWasm discussion forums or open an issue!
We've made some changes to our internal build infrastructure, which should make it easier for us to track upstream Swift changes. Now GitHub swiftwasm/swift repository is just for hosting our release artifacts, and we're maintaining our downstream changes in traditional .patch
file format in swiftwasm/swiftwasm-build repository. See our rationale if you're interested in the details of this decision.
We'd like to thank our GitHub sponsors and OpenCollective contributors for their support, which allowed us to continue working on SwiftWasm and related projects. We are displaying our gold sponsors on the README of swiftwasm/swift repository. If you are already a gold sponsor and not yet listed, please contact Yuta Saito to add your appropriate logo.
We're committed to publishing transparent and open finances, so all expenses and transactions can be viewed publicly on our OpenCollective Transactions page.
So far we've spent money on monthly CI bills that cover new aarch64
CPU architecture and community CI, domain registration, email hosting, and development hardware for our maintainers.
Many thanks to MacStadium for giving us access to Apple Silicon hardware.
Additionally, we'd like to thank everyone who contributed their work and helped us make this release happen. These new releases wouldn't be possible without the hard work of them and the Swift community as a whole.
]]>We're happy to announce the new release of SwiftWasm tracking upstream Swift 5.8!
Notable WebAssembly-specific changes in this release:
x86_64
architecture. (Note that aarch64
support is available only for macOS and Ubuntu 20.04 for now.)ghcr.io/swiftwasm/swift
Docker image is now based on Ubuntu 22.04 by default for latest
and 5.8
tags.As for changes in upstream Swift 5.8, we recommend referring to the official changelog.
For more information about SwiftWasm in general and for getting started, please visit the project documentation. If you have any questions, please come and talk to us on the SwiftWasm discussion forums or open an issue!
We'd like to thank our GitHub sponsors and OpenCollective contributors for their support, which allowed us to continue working on SwiftWasm and related projects.
We're committed to publishing transparent and open finances, so all expenses and transactions can be viewed publicly on our OpenCollective Transactions page.
So far we've spent money on monthly CI bills that cover new aarch64
CPU architecture and community CI, domain registration, email hosting, and development hardware for our maintainers.
Many thanks to MacStadium for giving us access to Apple Silicon hardware.
Additionally, we'd like to thank everyone who contributed their work and helped us make this release happen. These new releases wouldn't be possible without the hard work of them and the Swift community as a whole.
We forgot to announce the last release of SwiftWasm 5.7 in this blog, so here's a quick summary of what was included in that release:
Task.sleep
was added.We're happy to announce the new release of SwiftWasm tracking upstream Swift 5.6!
Notable WebAssembly-specific changes in this release:
aarch64
and Amazon Linux 2 on x86_64
architectures.With 5.6 release, when building SwiftWasm apps manually with swift build
, you should pass -Xswiftc -Xclang-linker -Xswiftc -mexec-model=reactor
flags to enable the "reactor" mode. When building with carton
, "reactor" model is enabled automatically.
As for changes in upstream Swift 5.6, we recommend referring to the official changelog. For convenience, here are some of the Swift Evolution proposals included in the release:
String
/Int
keyed Dictionary
into a KeyedContainer
Sendable
conformance from unsafe pointer typesany
JavaScriptKit 0.14 is a breaking release that enables full support for SwiftWasm 5.6 and lays groundwork for future updates to DOMKit.
Specifically, the ConvertibleToJSValue
conformance on Array
and Dictionary
has been swapped from the equality == ConvertibleToJSValue
clause to the inheritance : ConvertibleToJSValue
clause.
[String]
is now ConvertibleToJSValue
, but [ConvertibleToJSValue]
no longer conforms.jsValue()
method still works in both cases..map { $0.jsValue() }
(or mapValues
) to get an array/dictionary of JSValue
which you can then use as ConvertibleToJSValue
.jsValue
to the end of all values in an array/dictionary literal.The 0.14 release of carton
uses SwiftWasm 5.6.0 as the default toolchain. Additionally, issue with rebuilding projects when watching for file changes with carton dev
has been fixed. Also, please refer to release details for carton
0.13.0 for more information on new recently introduced --debug-info
and -Xswiftc
command-line flags.
Tokamak 0.10.0 adds support for SwiftWasm 5.6. It also updates JavaScriptKit and OpenCombineJS dependencies. Due to issues with support for older SwiftWasm releases in the carton/SwiftPM integration, Tokamak now requires SwiftWasm 5.6 or later, while SwiftWasm 5.4 and 5.5 are no longer supported.
As may already know, our OpenCollective page is the main way to financially support us. We're committed to publishing transparent and open finances, so we are excited to announce that all expenses and transactions can be viewed publicly on our OpenCollective Transactions page.
So far we've spent money on monthly CI bills that cover new aarch64
CPU architecture and Linux distributions, domain registration, email hosting, and development hardware for our maintainers.
We'd like to thank our GitHub sponsors and OpenCollective contributors for their support, which allowed us to continue working on SwiftWasm and related projects.
Many thanks to MacStadium for giving us access to Apple Silicon hardware. Without their help it would be close to impossible to set up CI for enabling full M1 support in our toolchain.
Additionally, we'd like to thank everyone who contributed their work and helped us make this release happen. These new releases wouldn't be possible without the hard work of (in alphabetical order):
...and to all of our users, and everyone working on the Swift project and libraries we depend on!
]]>We're happy to announce the new release of SwiftWasm tracking upstream Swift 5.5! Notably, in this release we've added support for async
/await
. This new feature of Swift can be integrated with JavaScript promises when you're using a new version of JavaScriptKit that was recently tagged. See the corresponding section below for more details.
Since multi-threading in WebAssembly is still not supported across all browsers (Safari is the only one lagging behind), this release of SwiftWasm doesn't include the Dispatch library and ships with a single-threaded cooperative executor. This means that actor
declarations in your code will behave as plain reference types and will all be scheduled on the main thread. If you need true parallel computation, you’ll have to write custom code against the Web Workers API (either via JavaScriptKit or delegating to raw JavaScript) to synchronize multiple SwiftWasm runtimes.
Additionally, 5.5.0 is the first release of SwiftWasm that supports Apple Silicon natively. The latest version of carton
(0.12.0) will download the arm64
distribution on Apple Silicon devices.
The 0.11 release of JavaScriptKit adds support for async
/await
and JSPromise
integration. Now instances of this class have an effectful async
property value
. Here's example code that shows you how can fetch
browser API be used without callbacks:
import JavaScriptKit
+import JavaScriptEventLoop
+
+// This line is required for `JSPromise.value` to work.
+JavaScriptEventLoop.installGlobalExecutor()
+
+private let jsFetch = JSObject.global.fetch.function!
+func fetch(_ url: String) -> JSPromise {
+ JSPromise(jsFetch(url).object!)!
+}
+
+struct Response: Decodable {
+ let uuid: String
+}
+
+let alert = JSObject.global.alert.function!
+let document = JSObject.global.document
+
+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)
+
Also, in this version of JavaScriptKit we're simplifying the JSClosure
API. You no longer need to release instances of this class manually, as they will be automatically garbage-collected by the browser after neither your Swift code nor the JavaScript runtime hold any references to them. This is achieved with the new
FinalizationRegistry
Web API, for which we had to significantly increase minimum browser versions required for JavaScriptKit to work. See README.md
in the project repository for more details.
We have to mention that there's still a possibility of reference cycles with this new API. FinalizationRegistry
doesn't implement full GC for JS closures, but it only solves dangling closure issue. For example, in this code
var button = document.createElement("button")
+button.onclick = .object(JSClosure { [button] in
+ // this capture makes a reference cycle
+ print(button)
+})
+
a reference cycle is created
┌─> JSObject (button in Swift) -> HTMLElement (button in JS) ────┐
+└── JSClosure (onclick in Swift) <─> Closure (onclick in JS) <───┘
+
In this case, when button
element is removed from the main DOM tree, it cannot be deallocated. The onclick
closure is still referenced by the button itself. These reference cycles can be resolved with the usual weak
captures you're probably used to writing in your AppKit and UIKit code.
Based on the improvements to JavaScriptKit and major work by our contributors, we're also tagging a new 0.9.0 release of Tokamak, a SwiftUI-compatible framework for building browser apps with WebAssembly. We've added:
Canvas
and TimelineView
types;onHover
modifier;task
modifier for running async
functions;Text
view.Tokamak v0.9.0 now requires Swift 5.4 or newer. Swift 5.5 (with SwiftWasm 5.5 when targeting the browser environment) is recommended.
We'd like to thank our sponsors for their support, which allowed us to continue working on the SwiftWasm toolchain and related projects.
Many thanks to MacStadium for giving us access to Apple Silicon hardware. Without their help it would be close to impossible to set up CI for enabling full M1 support in our toolchain.
Additionally, we'd like to thank everyone who contributed their work and helped us make this release happen. These new releases wouldn't be possible without the hard work of (in alphabetical order):
Happy New Year everyone! Here's a digest of what happened with SwiftWasm in December of 2020, published with a slight delay (it's 2021 already after all 😅).
One thing we forgot to mention in our November update is that the SwiftWasm community now has its own Discord server. In case you prefer Slack to Discord, we recommend you to join the #webassembly
channel in the SwiftPM Slack workspace.
In December we saw a lot of projects built with SwiftWasm shared by the community. Here a few most noteworthy:
Ever wanted to contribute to SwiftWasm projects, but unsure where to start? Here's a list of issues that could be suitable for beginners:
carton test
--enable-test-discovery
is now deprecated--host
option to carton dev
and carton test
We're working on tracking down all the possible edge cases when porting code from other platforms in the SwiftWasm book. Previously we were asked how to port code that depends on the Darwin
module on Apple platforms or Glibc
on Linux. We recommend using the WASILibc
module, which obviously somewhat differs from libc on other platforms. We've added a corresponding note clarifying this to the book.
As the Swift team already announced the release process for the 5.4 version, we started preparing our corresponding SwiftWasm 5.4 release. The swiftwasm-release/5.4
branch in our fork now tracks the upstream release/5.4
branch, as we plan to tag our own 5.4.0 later this year.
Additionally, we made sure that the fork of our toolchain can be compiled on Apple Silicon Macs. While GitHub Actions doesn't provide CI agents for the M1 architecture, the SwiftWasm toolchain can be built locally for Apple Silicon, and we hope to provide a prebuilt distribution archive for it in some future release.
@kateinoigakukun enabled experimental concurrency support in SwiftWasm and fixed several issues that previously prevented us from enabling async
/await
in development snapshots. Currently, starting with swift-wasm-DEVELOPMENT-SNAPSHOT-2021-01-02-a, the toolchain only supports a single-threaded task executor. This executor is suitable for usage in standalone WASI hosts such as Wasmer or Wasmtime. Unfortunately, it blocks the JavaScript event loop until all jobs are completed, and is unable to run any jobs created after the first event loop cycle. While this makes it unsuitable for JavaScript environments, we were able to work around that in JavaScriptKit as discussed in the next section.
@kateinoigakukun started implementing a Swift concurrency task executor integrated with the JavaScript event loop. There are still several issues, but it's working well as a proof of concept. This experimental API allows us to utilize async
/await
in SwiftWasm apps for browsers and Node.js like this:
import JavaScriptEventLoop
+import JavaScriptKit
+
+JavaScriptEventLoop.install()
+let fetch = JSObject.global.fetch.function!.async
+
+func printZen() async {
+ let result = try! await fetch("https://api.github.com/zen").object!
+ let text = try! await result.asyncing.text!()
+ print(text)
+}
+
+JavaScriptEventLoop.runAsync {
+ await printZen()
+}
+
@kateinoigakukun published a Swift WebAssembly runtime package powered by the WebAssembly Micro Runtime project (WAMR). This allows us to remove Wasmer dependency from carton
and embed the WebAssembly runtime in the carton
binary for use in commands such as carton test
.
We were also able to test this package on Apple Silicon and submit a PR upstream to make it work.
Our long-term goal is to make DOMKit the recommended library for type-safe interactions with Web APIs in SwiftWasm. While it's still at an early stage, we've updated it to JavaScriptKit 0.9 and added support for globalThis
. In a separate PR we've cleaned up unused code and fixed an event handlers crash.
With enough changes to warrant a new release, we've published Tokamak 0.6.0, which introduced support for the Image
view loading images bundled as SwiftPM resources, implemented by @j-f1. It also adds the PreferenceKey
protocol and related modifiers. developed by @carson-katri.
Since then we've also added the PreviewProvider
protocol, an implementation of TextEditor
, and updated our example code in README.md
for script injection. Additionally, a contribution from David Hunt added missing typealiases to TokamakDOM that should improve compatibility with SwiftUI, while Jed Fox removed redundant path
element from SVG output.
carton
We'd like to welcome @thecb4, who is the latest addition to the carton
maintainers team! Thanks to his work, project targets were restructured for better testability, and now test
, dev
, and bundle
commands are covered with end-to-end tests.
There's ongoing work to integrate the WAMR package mentioned above with the carton test
command. Also, carton
now correctly handles system target dependencies in Package.swift
.
On top of that, stack traces from Chrome and Safari are now supported in carton dev
with proper symbol demangling, thanks to the work by @j-f1. Additionally, @yonihemi submitted a PR which integrates carton
with libSwiftPM allowing us to reuse its model types.
Most of these changes were included in 0.9.0 and 0.9.1 releases published in December.
webidl2swift
webidl2swift
is the foundation on which our DOMKit framework is built. Web API across all browsers is specified in the Web IDL format, which can then be parsed to generate type-safe bindings in Swift. The parser doesn't support all IDL files out there yet, but we've updated dependencies and updated the code generator to certain JavaScriptKit types that previously were deprecated.
There were a few changes to the WasmTransformer package, which we use in carton
and intend to use in a few other dev tools. Specifically, we've generalized section info parsing across different transformers, implemented a basic section size profiler, and made the TypeSection
type public to make it easier to analyze sections of WebAssembly binaries.
We're excited to announce our new developer tool enabled by WasmTransformer. Gravity is a binary code size profiler for WebAssembly built with WasmTransformer, SwiftUI, and TCA. It's an application for macOS that allows you to open a WebAssembly binary and view the size of different sections. Contents of some of the sections is also parsed for further analysis.
A lot of our progress with SwiftWasm wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on our SwiftWasm organization sponsorship page, or personal sponsorship pages of Carson Katri, Yuta Saito and Max Desiatov.
Thanks for reading! 👋
]]>As you may have seen in our previous post, we've published our first stable release recently. Shortly after that, @flavio reported an issue with JSONDecoder
. Following an investigation by @kateinoigakukun into the root cause of the issue, we've published SwiftWasm 5.3.1, which also included updates from the upstream 5.3.1 patch release.
(If you're interested in technical details, the JSONDecoder
issue was caused by a peculiar assumption about memory layout in Swift runtime, which wasn't applicable to WebAssembly's linear memory. Check the PR diff for more details.)
A major update since the latest 0.8.0 release of JavaScriptKit is newly added support for throwing functions developed by @kateinoigakukun. It required an update to the JavaScript runtime part, but was an additive change to the Swift API. As we try to publish releases regularly, new 0.9.0 release was tagged that includes this feature.
A PR with support for Asyncify transformation was created by @yonihemi. It allows calling asynchronous JavaScript APIs with Swift code that looks as plain synchronous code, but through proper suspension that doesn't block browser rendering. The PR has some implications on how we build things, especially as it requires a specific optimizer transformation. It is still in the draft stage, and you're welcome to contribute to the ongoing discussion.
We still use a fork of OpenCombine in Tokamak due to our custom implementation of the ObservableObject
protocol. In addition to that, our fork also contained some changes to the package manifest to make it build with SwiftWasm, but they made it incompatible with non-Wasm platforms. This issue was resolved in the upstream OpenCombine repository, which reduced the amount of customizations we apply, and brings us closer to using the upstream repository as is.
With progress on OpenCombine, it was time to publish the first version of OpenCombineJS. Its code didn't change recently, but parts of it were used in Tokamak already, which gave us confidence that it was reliable enough to be released in a separate library for wider use. It currently doesn't contain much code, but this basic functionality should be enough for basic integration of JavaScriptKit types and OpenCombine.
Following the 0.5.0 release, which added support for the latest carton
, we published a small 0.5.1 patch with support for editing Tokamak projects in Xcode with working autocomplete. Not long after that an important bugfix landed in 0.5.2, which fixed an issue with display order of updated views in the DOM renderer. A few weeks later another bugfix release was published as 0.5.3. In this update Tokamak now internally relies on the aforementioned OpenCombineJS library instead of providing its own JSScheduler
type conforming to Combine's Scheduler
. More importantly, it fixes a bug with Toggle
not being updated after resetting it from a binding.
@kateinoigakukun implemented a stripCustomSections
transformation in the WasmTransformer
library. According to the spec, data in custom sections should not contribute to observed behavior of a given binary. In the case of binaries produced by SwiftWasm, custom sections contain debugging information that can now be stripped with
WasmTransformer
.
carton
Previously, custom sections were stripped to reduce final binary size as a build step in `carton bundle with the
wasm-strip` utility from WABT. Thanks to the new transformation in WasmTransformer
, WABT is no longer needed as a dependency of carton
, which makes installation for our end users simpler and faster.
Initial support for presenting crash stack traces directly in carton
has been completed, starting with Firefox support. Support for more browsers will be added in separate PRs.
There was also work on file downloader cleanup, support for browser testing, and simpler URLs for main bundle resources. As soon as these are merged, a new version of carton
will be tagged that will use the latest 5.3.1 release of SwiftWasm.
A lot of the progress wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on the sponsorship pages of Carson Katri, Yuta Saito and Max Desiatov.
Thanks for reading! 👋
]]>This is the first public release of SwiftWasm toolchain, available as a signed .pkg installer for macOS. Also via swiftenv-compatible archives and Docker for Intel-based Ubuntu 18.04 and 20.04. Our focus is on providing essential Swift features for the WebAssembly platform. Distributions supplied with this release are our most stable yet, and no breaking changes are expected for 5.3 releases anymore.
This release includes the Swift for WebAssembly compiler, the standard and core libraries (excluding Dispatch), JavaScript interoperation library, UI library, build tool and CI support.
The Swift standard library is fully available on WebAssembly platform.
The standard library right now depends on WASI, which is a modular system interface for WebAssembly. We use the wasi-libc implementation, which you can also use in your Swift apps with a simple import WASILibc
statement. However, we are going to make the WASI dependency optional in the future.
Foundation and XCTest are also available on WebAssembly, but in a limited capacity.
Please refer to our Foundation and XCTest guides for more details.
JavaScriptKit is a Swift library to interact with JavaScript through WebAssembly.
You can use any JavaScript API from Swift with this library. Here's a quick example of JavaScriptKit usage in a browser app:
import JavaScriptKit
+
+let document = JSObject.global.document
+
+var divElement = document.createElement("div")
+divElement.innerText = "Hello, world"
+_ = document.body.appendChild(divElement)
+
You can learn more from our JavaScript interop guide.
The Tokamak UI framework is a cross-platform implementation of the SwiftUI API. We currently only support WebAssembly/DOM with a lot of API parts covered, and static HTML rendering on macOS/Linux. Get started with our browser apps guide that lists necessary steps to create a simple browser app with Tokamak.
carton
is a build tool designed specifically for SwiftWasm. It is similar to webpack.js, but no configuration and dependencies (except Swift itself to build carton
) are required. It's also our recommended way to install SwiftWasm as it downloads and unpacks our toolchain and SDK automatically for you.
We maintain a GitHub Action that includes the SwiftWasm toolchain and carton
for your continuous integration needs.
@hassan-shahbazi wrote a 3 part guide about his experience when integrating SwiftWasm apps within Go apps through Wasmer. He also published example code accompanying the articles on GitHub. It's a great introduction to SwiftWasm that doesn't assume much prior knowledge, and could be useful if you'd like to integrate binaries produced by SwiftWasm in a host application.
@johngarrett published an interactive "Swift, Wasm, and Algorithms" documentation page. It is a demo of the recently released Swift Algorithms package where you can tweak parameters for some of the functions and observe results directly in the browser. Not all of the functions are fully interactive now, but it's a great proof of concept for interactive documentation websites one could build with SwiftWasm. Its source code is available on GitHub.
Two new sections were added to the SwiftWasm book that clarify limitations of Foundation, and recommended ways to use XCTest with the SwiftWasm SDK.
@kateinoigakukun published a pure Swift implementation of a transformer for Wasm binaries. This resolves the issue with i64
to BigInt
incompatibility in Safari, as we can now integrate an appropriate transformation into our build pipeline in carton
. The WasmTransformer
library is still at an early stage, but it shows that Swift is suitable for low-level code just as well as C/C++ or Rust.
carton
In addition to the WasmTransfomer integration mentioned above, carton test
now passes the --enable-test-discovery
flag to swift test
by default, which means that you no longer need to maintain LinuxMain.swift
and XCTestManifests.swift
files in your test suites.
A Dockerfile
was added to the carton
repository, and you can now run carton
in a Docker container, which also has the toolchain and other dependencies preinstalled. You can pull the Docker image with a simple command:
docker pull ghcr.io/swiftwasm/carton:latest
+
Additionally, carton
gained support for Ubuntu 20.04, and now also has a CI job to test compatibility with it during development. Similarly, a CI job for macOS Big Sur on Intel platforms was added as soon as GitHub Actions started providing appropriate CI images.
After these changes were merged carton
0.7 was released and is now available via Homebrew on macOS.
After the release, @carson-katri merged a PR that greatly improves command-line experience with carton test
. It builds on his previous work on carton dev
with compiler diagnostics parsing and error highlighting. With this new change XCTest output is also parsed, reformatted, and highlighted in a nice summary view.
Thanks to the fact that carton
is now available in a Docker image, it can now be used in our swiftwasm-action
, which previously only contained the plain SwiftWasm toolchain without any additional tools. This action now invokes carton test
by default on a given repository during a GitHub Actions run, but you can customize it and call any other command. For example, you could run carton bundle
with swiftwasm-action
, and then use the peaceiris/actions-gh-pages
step to deploy the resulting bundle to GitHub Pages.
JavaScriptKit 0.8.0 has been released. As mentioned in our previous issue, it introduces a few enhancements and deprecations, and is a recommended upgrade for all users.
@Cosmo pointed out that SwiftUI apps should change almost the whole palette when switching between color schemes. As he discovered when working on his OpenSwiftUI and SwiftUIEmbedded projects, the implementation of the Color
type is much more subtle than we originally anticipated. This was resolved by @carson-katri in #291 and is now available in the main
branch. The plan is to merge a few more changes and bugfixes, and to tag a new release of Tokamak soon after that.
@owenv merged a PR to the Swift Driver project implementing WebAssembly toolchain support. This mirrors our existing C++ implementation in the legacy driver, and it's great that the new parts of the Swift compiler rewritten in Swift are going to support WebAssembly too. While Swift Driver isn't enabled in any toolchain by default, we're definitely going to enable it at some point in the future as soon as it seems to be stable enough for us.
@kateinoigakukun submitted a PR to SwiftPM that propagates the -static-stdlib
flag correctly to the compiler driver. After it was merged, we were able to remove a bit of code that generated SwiftPM destination files to ensure correct linking, and this is no longer needed thanks to the upstream changes.
@MaxDesiatov merged a PR to Swift TSC that adds .wasm
file extension to WebAssembly binaries produced by SwiftPM. This extension was previously missing, which didn't make it obvious enough that these binaries can't be run without passing them to an appropriate WebAssembly host.
In preparation for the 5.3.0 release of SwiftWasm, our macOS archives are now distributed as signed .pkg
installers. Also need to mention that the toolchain archive is now available for Ubuntu 20.04, and all archive files now have consistent naming that includes the full OS name and CPU architecture. This will make it much easier for us to distribute ARM64 builds and builds for other Linux distributions in the future.
Another change to be included in 5.3 snapshots would add .wasm
file extension to binaries reflecting aforementioned upstream PRs.
Additionally, we found that it's currently not possible to build C++ code that includes certain headers with SwiftWasm 5.3 snapshots. As some Swift libraries do have C++ targets as their dependencies, it would be great if this is fixed before SwiftWasm 5.3.0 is tagged.
We'll be using latest 5.3 snapshots in our apps and libraries for some time, and will tag 5.3.0 when we have enough confidence there are no major issues.
The wasm-DEVELOPMENT-SNAPSHOT
archives will continue to be tagged on a regular basis to serve as a preview of the next version of SwiftWasm, but are not recommended for general use.
A lot of the progress wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on the sponsorship pages of Carson Katri, Yuta Saito and Max Desiatov.
Thanks for reading! 👋
]]>Welcome to the second SwiftWasm update! To make the updates flow steady, we're trying to publish them fortnightly now. Let us know what you think of this new cadence. And here's a gentle reminder that this blog is fully open-source, so if you spot a typo, an error, a broken link, or have any other feedback, please feel free to file it in our blog.swiftwasm.org
GitHub repository.
We would like to welcome @yonihemi to the SwiftWasm team who joined us in the beginning of October. After the previous contributions he made to carton
it made perfect sense to expand our team. As always, we invite everyone to contribute to any of our repositories, and it doesn't require much prior experience with SwiftWasm if any at all. Bug fixes, feature additions, improved documentation and related changes are very much appreciated and allow our ecosystem to grow even more!
Our documentation was restructured and updated, and is now hosted on the book.swiftwasm.org
domain. Please file all feedback in the swiftwasm-book
repository on GitHub, which hosts its source code.
JavaScriptKit had a few important updates in October so far. Most importantly, now that PR #91 by @kateinoigakukun was merged, JavaScriptKit no longer uses unsafe flags in its Package.swift
. The use of unsafe flags was a big problem for us, as it breaks dependency resolution due to strict checks that SwiftPM applies. If any package in your dependency tree contains unsafe flags, you can no longer depend on its semantic version, or a semantic version of any other package that depends on it.
So far we were able to work around that with a hardcoded check for JavaScriptKit in our fork of SwiftPM. This was obviously a very ugly hack, but the biggest downside of that approach was that you couldn't depend on any package that had a semantic version dependency on JavaScriptKit in upstream Swift toolchains. That meant that libraries like Tokamak could not be built for macOS or Linux. And while the WebAssembly DOM renderer in Tokamak is the most useful module right now, this prevented static HTML rendering from working on macOS and Linux.
Another issue we had with JavaScriptKit is the naming of JSValueConstructible
and JSValueConvertible
protocols. These protocols are used for conversions between JSValue
references and arbitrary Swift values. In practice it wasn't always clear which of these protocols was responsible for a specific conversion. After some deliberation, these were renamed to ConstructibleFromJSValue
and ConvertibleToJSValue
respectively in #88.
A proposal PR was submitted by @kateinoigakukun to enable unsafe force unwrapping of dynamic member properties in JavaScript by default. That is, it would allow this
let document = JSObject.global.document
+let foundDivs = document.getElementsByTagName("div")
+
in addition to the currently available explicit style with force unwrapping:
let document = JSObject.global.document.object!
+let foundDivs = document.getElementsByTagName!("div").object!
+
The key thing to note is that the first option is still dynamically typed and these options are equivalent in their behavior. If you address a missing property on your JavaScript object with this API, your SwiftWasm app will crash. One possible reasoning for this change is that this would follow the approach of PythonKit and Swift for TensorFlow, and improve readability and ease of use for newcomers. We encourage you to voice your opinion in PR comments to give us more feedback on this proposal.
An issue was raised by @yonihemi this week on our JavaScriptKit repository about i64
Wasm function return type support in Safari. The reason for it is that Safari is the only major browser that doesn't support Wasm i64
to BigInt
conversion. Unfortunately, there are many APIs that require this conversion to work, and it's unclear yet if this can be polyfilled on the JavaScript side at all. Currently it looks like we need to apply some transformations to binaries produced by SwiftWasm to resolve this issue, but it remains to be seen how well that would work in practice.
Tokamak didn't see major updates recently, but we've received some important bug reports during the last few weeks. Firstly, there's an edge case with Picker
views that use \.self
as an identifier keypath. Secondly, Toggle
binding is not reset after its value changes outside of the view. Many thanks to @rbartolome for the extensive testing he's given and for reporting these issues!
In the first half of October @yonihemi submitted two important quality-of-life improvements to carton
:
There's also an open "Pretty print diagnostics" PR #112 submitted by @carson-katri. It does some magic with diagnostic messages emitted by the Swift compiler, highlights relevant lines of code and formats all of it nicely. You can check out a preview on this screenshot:
Not much upstreaming work happened in October yet, but there was some progress in adding cross-compilation support to SourceKit-LSP. We are also preparing a 5.3 SwiftWasm snapshot with this patch, which will enable this new --destination
option on SourceKit-LSP. When that works, we want carton
to infer a value for this option and launch it automatically for you when needed. This is all to make auto-complete work correctly for your SwiftWasm apps and libraries in VSCode or any other LSP-supporting editor or IDE.
Most of the work in preparation for the 5.3.0 release of SwiftWasm has been done. Now that it's possible to build JavaScriptKit without unsafe flags, and with IndexStoreDB and SourceKit-LSP shipping with the latest 5.3.0 snapshots, only the last round of testing is needed before tagging a release candidate. The rest of our work on the SwiftWasm toolchain and SDK was mostly related to fixing a build breakage caused by updates to GitHub Actions runner images and resolving conflicts with upstream code.
A lot of the progress wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on the sponsorship pages of Carson Katri, Yuta Saito and Max Desiatov.
Thanks for reading! 👋
]]>Welcome to the SwiftWasm blog! The amount of work happening in the SwiftWasm ecosystem is growing, so we decided to start publishing blog updates to give you an overview of what happened recently. This update for September is big enough to be split into different sections for each area of our work, so let's get started. 🙂
JavaScriptKit 0.7 has been released. It adds multiple new types bridged from JavaScript, namely JSError
, JSDate
, JSTimer
(which corresponds to setTimeout
/setInterval
calls and manages closure lifetime for you), JSString
and JSPromise
. We now also have documentation published automatically for the main
branch.
New features of JavaScriptKit allowed us to start working on closer integration with OpenCombine. The current progress is available in the new OpenCombineJS repository, and we plan to tag a release for it soon. At the moment it has a JSScheduler
class wrapping JSTimer
that implements the Scheduler
protocol, enabling you to use debounce
and other time-based operators. Additionally, OpenCombineJS now provides a helper publisher
property on JSPromise
, which allows you to integrate any promise-based API with an OpenCombine pipeline.
We also saw a lot of great progress with DOMKit in September thanks to the outstanding work by Jed Fox and @Unkaputtbar, which was unblocked by the recent additions to JavaScriptKit. With DOMKit we're going to get type-safe access to the most common browser DOM APIs. It will be expanded in the future to support even more features that currently are only available via JavaScriptKit through force unwrapping and dynamic casting.
That is, compare the current API you get with JavaScriptKit:
import JavaScriptKit
+
+let document = JSObject.global.document.object!
+
+let divElement = document.createElement!("div").object!
+divElement.innerText = "Hello, world"
+let body = document.body.object!
+_ = body.appendChild!(divElement)
+
to an equivalent snippet that could look like this with DOMKit:
import DOMKit
+
+let document = global.document
+
+let divElement = document.createElement("div")
+divElement.innerText = "Hello, world"
+document.body.appendChild(divElement)
+
Lastly on the libraries front, Tokamak 0.4 is now available, enabling compatibility with the new version of JavaScriptKit, and utilizing the aforementioned JSScheduler
implementation.
Following the new 0.7 release of JavaScriptKit, carton
0.6 has been tagged, shipping with the appropriate JavaScriptKit runtime compatible with the new release. It also includes support for the new carton bundle
command that produces a directory with optimized build output ready for deployment on a CDN or any other server. Notably, both carton bundle
and carton dev
support SwiftPM package resources, allowing you to include additional static content in your SwiftWasm apps. These could be styles, scripts, images, fonts, or whatever other data you'd like to ship with your app.
This version of carton
also ships with the latest version of wasmer.js, which fixes compatibility with recently released Safari 14.
The upstream Swift toolchain has switched to LLVM 11 in the main
branch, which caused a substantial amount of conflicts in our forked repositories. Resolving the conflicts and making sure everything builds properly consumed a lot of our time in September. You could've noticed that the previously steady stream of nighly development snapshots stalled for most of September, but it resumed starting with wasm-DEVELOPMENT-SNAPSHOT-2020-09-20-a
.
As for the 5.3 branch, with the upstream Swift 5.3.0 release now generally available, we're now preparing a stable SwiftWasm 5.3.0 release. It is based off upstream 5.3.0 with our patches applied to the toolchain and the SDK. We've created a checklist that allows us to track the progress of this effort.
One of the issues we wanted to resolve before tagging SwiftWasm 5.3.0 is the inconsistency between WASI and Glibc APIs. While parts of those look and works the same, the rest are significantly different. Because of this, in subsequent snapshots our users need to use import WASILibc
instead of import Glibc
if they need to access to libc on the WASI platform. This has already landed in the swiftwasm-release/5.3
branch with swiftwasm/swift#1773 and is available in wasm-5.3-SNAPSHOT-2020-09-23-a
or later. It was also implemented in the main swiftwasm
branch in swiftwasm/swift#1832, all thanks to the amazing work by Yuta Saito.
The divergence between the SwiftWasm toolchain/SDKs and their upstream version is still significant and causes regular conflicts that we have to resolve manually. We're working on making our changes available upstream, but this takes a lot of time, as upstream toolchain and SDK PRs need high level of polish to be accepted. Here's a list of PRs that had some progress in September:
TARGET_OS_WASI
in CFLocking.h
apple/swift-corelibs-foundation#2867. Status: merged.CFInternal.h
apple/swift-corelibs-foundation#2872. Status: merged.CoreFoundation_Prefix.h
apple/swift-corelibs-foundation#2873. Status: merged.CFDate.c
apple/swift-corelibs-foundation#2880. Status: in review.We hope you can contribute to the SwiftWasm ecosystem, either to any of the projects listed above, or with your own libraries and apps that you built. We'd be very happy to feature your open-source work in our next update! Our swiftwasm.org
website and this blog are open-source, so please feel free to open an issue or a pull request with a link to your work related to SwiftWasm.
A lot of the progress wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on the sponsorship pages of Yuta Saito and Max Desiatov.
Thanks for reading! 👋
]]>SwiftWasm 5.9.1 has been released.
SwiftWasm 5.8.0 has been released.
SwiftWasm 5.6.0 has been released.
SwiftWasm 5.5.0 with support for async/await and Apple Silicon has been released.
An update on what happened in the SwiftWasm ecosystem during December 2020.
An update on what happened in the SwiftWasm ecosystem during November 2020.
Our stable 5.3 release of the toolchain is now available
An update on what happened in the SwiftWasm ecosystem during the second half of October 2020.
An update on what happened in the SwiftWasm ecosystem during the first half of October 2020.
An update on what happened in the SwiftWasm ecosystem during September 2020.
Published on
This is the first public release of SwiftWasm toolchain, available as a signed .pkg installer for macOS. Also via swiftenv-compatible archives and Docker for Intel-based Ubuntu 18.04 and 20.04. Our focus is on providing essential Swift features for the WebAssembly platform. Distributions supplied with this release are our most stable yet, and no breaking changes are expected for 5.3 releases anymore.
This release includes the Swift for WebAssembly compiler, the standard and core libraries (excluding Dispatch), JavaScript interoperation library, UI library, build tool and CI support.
The Swift standard library is fully available on WebAssembly platform.
The standard library right now depends on WASI, which is a modular system interface for WebAssembly. We use the wasi-libc implementation, which you can also use in your Swift apps with a simple import WASILibc
statement. However, we are going to make the WASI dependency optional in the future.
Foundation and XCTest are also available on WebAssembly, but in a limited capacity.
Please refer to our Foundation and XCTest guides for more details.
JavaScriptKit is a Swift library to interact with JavaScript through WebAssembly.
You can use any JavaScript API from Swift with this library. Here's a quick example of JavaScriptKit usage in a browser app:
import JavaScriptKit
+
+let document = JSObject.global.document
+
+var divElement = document.createElement("div")
+divElement.innerText = "Hello, world"
+_ = document.body.appendChild(divElement)
+
You can learn more from our JavaScript interop guide.
The Tokamak UI framework is a cross-platform implementation of the SwiftUI API. We currently only support WebAssembly/DOM with a lot of API parts covered, and static HTML rendering on macOS/Linux. Get started with our browser apps guide that lists necessary steps to create a simple browser app with Tokamak.
carton
is a build tool designed specifically for SwiftWasm. It is similar to webpack.js, but no configuration and dependencies (except Swift itself to build carton
) are required. It's also our recommended way to install SwiftWasm as it downloads and unpacks our toolchain and SDK automatically for you.
We maintain a GitHub Action that includes the SwiftWasm toolchain and carton
for your continuous integration needs.
Published on
We're happy to announce the new release of SwiftWasm tracking upstream Swift 5.5! Notably, in this release we've added support for async
/await
. This new feature of Swift can be integrated with JavaScript promises when you're using a new version of JavaScriptKit that was recently tagged. See the corresponding section below for more details.
Since multi-threading in WebAssembly is still not supported across all browsers (Safari is the only one lagging behind), this release of SwiftWasm doesn't include the Dispatch library and ships with a single-threaded cooperative executor. This means that actor
declarations in your code will behave as plain reference types and will all be scheduled on the main thread. If you need true parallel computation, you’ll have to write custom code against the Web Workers API (either via JavaScriptKit or delegating to raw JavaScript) to synchronize multiple SwiftWasm runtimes.
Additionally, 5.5.0 is the first release of SwiftWasm that supports Apple Silicon natively. The latest version of carton
(0.12.0) will download the arm64
distribution on Apple Silicon devices.
The 0.11 release of JavaScriptKit adds support for async
/await
and JSPromise
integration. Now instances of this class have an effectful async
property value
. Here's example code that shows you how can fetch
browser API be used without callbacks:
import JavaScriptKit
+import JavaScriptEventLoop
+
+// This line is required for `JSPromise.value` to work.
+JavaScriptEventLoop.installGlobalExecutor()
+
+private let jsFetch = JSObject.global.fetch.function!
+func fetch(_ url: String) -> JSPromise {
+ JSPromise(jsFetch(url).object!)!
+}
+
+struct Response: Decodable {
+ let uuid: String
+}
+
+let alert = JSObject.global.alert.function!
+let document = JSObject.global.document
+
+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)
+
Also, in this version of JavaScriptKit we're simplifying the JSClosure
API. You no longer need to release instances of this class manually, as they will be automatically garbage-collected by the browser after neither your Swift code nor the JavaScript runtime hold any references to them. This is achieved with the new
FinalizationRegistry
Web API, for which we had to significantly increase minimum browser versions required for JavaScriptKit to work. See README.md
in the project repository for more details.
We have to mention that there's still a possibility of reference cycles with this new API. FinalizationRegistry
doesn't implement full GC for JS closures, but it only solves dangling closure issue. For example, in this code
var button = document.createElement("button")
+button.onclick = .object(JSClosure { [button] in
+ // this capture makes a reference cycle
+ print(button)
+})
+
a reference cycle is created
┌─> JSObject (button in Swift) -> HTMLElement (button in JS) ────┐
+└── JSClosure (onclick in Swift) <─> Closure (onclick in JS) <───┘
+
In this case, when button
element is removed from the main DOM tree, it cannot be deallocated. The onclick
closure is still referenced by the button itself. These reference cycles can be resolved with the usual weak
captures you're probably used to writing in your AppKit and UIKit code.
Based on the improvements to JavaScriptKit and major work by our contributors, we're also tagging a new 0.9.0 release of Tokamak, a SwiftUI-compatible framework for building browser apps with WebAssembly. We've added:
Canvas
and TimelineView
types;onHover
modifier;task
modifier for running async
functions;Text
view.Tokamak v0.9.0 now requires Swift 5.4 or newer. Swift 5.5 (with SwiftWasm 5.5 when targeting the browser environment) is recommended.
We'd like to thank our sponsors for their support, which allowed us to continue working on the SwiftWasm toolchain and related projects.
Many thanks to MacStadium for giving us access to Apple Silicon hardware. Without their help it would be close to impossible to set up CI for enabling full M1 support in our toolchain.
Additionally, we'd like to thank everyone who contributed their work and helped us make this release happen. These new releases wouldn't be possible without the hard work of (in alphabetical order):
Published on
We're happy to announce the new release of SwiftWasm tracking upstream Swift 5.6!
Notable WebAssembly-specific changes in this release:
aarch64
and Amazon Linux 2 on x86_64
architectures.With 5.6 release, when building SwiftWasm apps manually with swift build
, you should pass -Xswiftc -Xclang-linker -Xswiftc -mexec-model=reactor
flags to enable the "reactor" mode. When building with carton
, "reactor" model is enabled automatically.
As for changes in upstream Swift 5.6, we recommend referring to the official changelog. For convenience, here are some of the Swift Evolution proposals included in the release:
String
/Int
keyed Dictionary
into a KeyedContainer
Sendable
conformance from unsafe pointer typesany
JavaScriptKit 0.14 is a breaking release that enables full support for SwiftWasm 5.6 and lays groundwork for future updates to DOMKit.
Specifically, the ConvertibleToJSValue
conformance on Array
and Dictionary
has been swapped from the equality == ConvertibleToJSValue
clause to the inheritance : ConvertibleToJSValue
clause.
[String]
is now ConvertibleToJSValue
, but [ConvertibleToJSValue]
no longer conforms.jsValue()
method still works in both cases..map { $0.jsValue() }
(or mapValues
) to get an array/dictionary of JSValue
which you can then use as ConvertibleToJSValue
.jsValue
to the end of all values in an array/dictionary literal.The 0.14 release of carton
uses SwiftWasm 5.6.0 as the default toolchain. Additionally, issue with rebuilding projects when watching for file changes with carton dev
has been fixed. Also, please refer to release details for carton
0.13.0 for more information on new recently introduced --debug-info
and -Xswiftc
command-line flags.
Tokamak 0.10.0 adds support for SwiftWasm 5.6. It also updates JavaScriptKit and OpenCombineJS dependencies. Due to issues with support for older SwiftWasm releases in the carton/SwiftPM integration, Tokamak now requires SwiftWasm 5.6 or later, while SwiftWasm 5.4 and 5.5 are no longer supported.
As may already know, our OpenCollective page is the main way to financially support us. We're committed to publishing transparent and open finances, so we are excited to announce that all expenses and transactions can be viewed publicly on our OpenCollective Transactions page.
So far we've spent money on monthly CI bills that cover new aarch64
CPU architecture and Linux distributions, domain registration, email hosting, and development hardware for our maintainers.
We'd like to thank our GitHub sponsors and OpenCollective contributors for their support, which allowed us to continue working on SwiftWasm and related projects.
Many thanks to MacStadium for giving us access to Apple Silicon hardware. Without their help it would be close to impossible to set up CI for enabling full M1 support in our toolchain.
Additionally, we'd like to thank everyone who contributed their work and helped us make this release happen. These new releases wouldn't be possible without the hard work of (in alphabetical order):
...and to all of our users, and everyone working on the Swift project and libraries we depend on!
Published on
We're happy to announce the new release of SwiftWasm tracking upstream Swift 5.8!
Notable WebAssembly-specific changes in this release:
x86_64
architecture. (Note that aarch64
support is available only for macOS and Ubuntu 20.04 for now.)ghcr.io/swiftwasm/swift
Docker image is now based on Ubuntu 22.04 by default for latest
and 5.8
tags.As for changes in upstream Swift 5.8, we recommend referring to the official changelog.
For more information about SwiftWasm in general and for getting started, please visit the project documentation. If you have any questions, please come and talk to us on the SwiftWasm discussion forums or open an issue!
We'd like to thank our GitHub sponsors and OpenCollective contributors for their support, which allowed us to continue working on SwiftWasm and related projects.
We're committed to publishing transparent and open finances, so all expenses and transactions can be viewed publicly on our OpenCollective Transactions page.
So far we've spent money on monthly CI bills that cover new aarch64
CPU architecture and community CI, domain registration, email hosting, and development hardware for our maintainers.
Many thanks to MacStadium for giving us access to Apple Silicon hardware.
Additionally, we'd like to thank everyone who contributed their work and helped us make this release happen. These new releases wouldn't be possible without the hard work of them and the Swift community as a whole.
We forgot to announce the last release of SwiftWasm 5.7 in this blog, so here's a quick summary of what was included in that release:
Task.sleep
was added.Published on
We're happy to announce the new release of SwiftWasm tracking upstream Swift 5.9.1!
This is a periodic release of SwiftWasm, which tracks the upstream Swift 5.9.1 release. As for changes in upstream Swift 5.9, we recommend referring to the official changelog.
For more information about SwiftWasm in general and for getting started, please visit the project documentation. If you have any questions, please come and talk to us on the SwiftWasm discussion forums or open an issue!
We've made some changes to our internal build infrastructure, which should make it easier for us to track upstream Swift changes. Now GitHub swiftwasm/swift repository is just for hosting our release artifacts, and we're maintaining our downstream changes in traditional .patch
file format in swiftwasm/swiftwasm-build repository. See our rationale if you're interested in the details of this decision.
We'd like to thank our GitHub sponsors and OpenCollective contributors for their support, which allowed us to continue working on SwiftWasm and related projects. We are displaying our gold sponsors on the README of swiftwasm/swift repository. If you are already a gold sponsor and not yet listed, please contact Yuta Saito to add your appropriate logo.
We're committed to publishing transparent and open finances, so all expenses and transactions can be viewed publicly on our OpenCollective Transactions page.
So far we've spent money on monthly CI bills that cover new aarch64
CPU architecture and community CI, domain registration, email hosting, and development hardware for our maintainers.
Many thanks to MacStadium for giving us access to Apple Silicon hardware.
Additionally, we'd like to thank everyone who contributed their work and helped us make this release happen. These new releases wouldn't be possible without the hard work of them and the Swift community as a whole.
Our stable 5.3 release of the toolchain is now available
SwiftWasm 5.5.0 with support for async/await and Apple Silicon has been released.
SwiftWasm 5.6.0 has been released.
SwiftWasm 5.8.0 has been released.
SwiftWasm 5.9.1 has been released.
An update on what happened in the SwiftWasm ecosystem during September 2020.
An update on what happened in the SwiftWasm ecosystem during the first half of October 2020.
An update on what happened in the SwiftWasm ecosystem during the second half of October 2020.
An update on what happened in the SwiftWasm ecosystem during November 2020.
An update on what happened in the SwiftWasm ecosystem during December 2020.
Published on
Welcome to the SwiftWasm blog! The amount of work happening in the SwiftWasm ecosystem is growing, so we decided to start publishing blog updates to give you an overview of what happened recently. This update for September is big enough to be split into different sections for each area of our work, so let's get started. 🙂
JavaScriptKit 0.7 has been released. It adds multiple new types bridged from JavaScript, namely JSError
, JSDate
, JSTimer
(which corresponds to setTimeout
/setInterval
calls and manages closure lifetime for you), JSString
and JSPromise
. We now also have documentation published automatically for the main
branch.
New features of JavaScriptKit allowed us to start working on closer integration with OpenCombine. The current progress is available in the new OpenCombineJS repository, and we plan to tag a release for it soon. At the moment it has a JSScheduler
class wrapping JSTimer
that implements the Scheduler
protocol, enabling you to use debounce
and other time-based operators. Additionally, OpenCombineJS now provides a helper publisher
property on JSPromise
, which allows you to integrate any promise-based API with an OpenCombine pipeline.
We also saw a lot of great progress with DOMKit in September thanks to the outstanding work by Jed Fox and @Unkaputtbar, which was unblocked by the recent additions to JavaScriptKit. With DOMKit we're going to get type-safe access to the most common browser DOM APIs. It will be expanded in the future to support even more features that currently are only available via JavaScriptKit through force unwrapping and dynamic casting.
That is, compare the current API you get with JavaScriptKit:
import JavaScriptKit
+
+let document = JSObject.global.document.object!
+
+let divElement = document.createElement!("div").object!
+divElement.innerText = "Hello, world"
+let body = document.body.object!
+_ = body.appendChild!(divElement)
+
to an equivalent snippet that could look like this with DOMKit:
import DOMKit
+
+let document = global.document
+
+let divElement = document.createElement("div")
+divElement.innerText = "Hello, world"
+document.body.appendChild(divElement)
+
Lastly on the libraries front, Tokamak 0.4 is now available, enabling compatibility with the new version of JavaScriptKit, and utilizing the aforementioned JSScheduler
implementation.
Following the new 0.7 release of JavaScriptKit, carton
0.6 has been tagged, shipping with the appropriate JavaScriptKit runtime compatible with the new release. It also includes support for the new carton bundle
command that produces a directory with optimized build output ready for deployment on a CDN or any other server. Notably, both carton bundle
and carton dev
support SwiftPM package resources, allowing you to include additional static content in your SwiftWasm apps. These could be styles, scripts, images, fonts, or whatever other data you'd like to ship with your app.
This version of carton
also ships with the latest version of wasmer.js, which fixes compatibility with recently released Safari 14.
The upstream Swift toolchain has switched to LLVM 11 in the main
branch, which caused a substantial amount of conflicts in our forked repositories. Resolving the conflicts and making sure everything builds properly consumed a lot of our time in September. You could've noticed that the previously steady stream of nighly development snapshots stalled for most of September, but it resumed starting with wasm-DEVELOPMENT-SNAPSHOT-2020-09-20-a
.
As for the 5.3 branch, with the upstream Swift 5.3.0 release now generally available, we're now preparing a stable SwiftWasm 5.3.0 release. It is based off upstream 5.3.0 with our patches applied to the toolchain and the SDK. We've created a checklist that allows us to track the progress of this effort.
One of the issues we wanted to resolve before tagging SwiftWasm 5.3.0 is the inconsistency between WASI and Glibc APIs. While parts of those look and works the same, the rest are significantly different. Because of this, in subsequent snapshots our users need to use import WASILibc
instead of import Glibc
if they need to access to libc on the WASI platform. This has already landed in the swiftwasm-release/5.3
branch with swiftwasm/swift#1773 and is available in wasm-5.3-SNAPSHOT-2020-09-23-a
or later. It was also implemented in the main swiftwasm
branch in swiftwasm/swift#1832, all thanks to the amazing work by Yuta Saito.
The divergence between the SwiftWasm toolchain/SDKs and their upstream version is still significant and causes regular conflicts that we have to resolve manually. We're working on making our changes available upstream, but this takes a lot of time, as upstream toolchain and SDK PRs need high level of polish to be accepted. Here's a list of PRs that had some progress in September:
TARGET_OS_WASI
in CFLocking.h
apple/swift-corelibs-foundation#2867. Status: merged.CFInternal.h
apple/swift-corelibs-foundation#2872. Status: merged.CoreFoundation_Prefix.h
apple/swift-corelibs-foundation#2873. Status: merged.CFDate.c
apple/swift-corelibs-foundation#2880. Status: in review.We hope you can contribute to the SwiftWasm ecosystem, either to any of the projects listed above, or with your own libraries and apps that you built. We'd be very happy to feature your open-source work in our next update! Our swiftwasm.org
website and this blog are open-source, so please feel free to open an issue or a pull request with a link to your work related to SwiftWasm.
A lot of the progress wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on the sponsorship pages of Yuta Saito and Max Desiatov.
Thanks for reading! 👋
Published on
Welcome to the second SwiftWasm update! To make the updates flow steady, we're trying to publish them fortnightly now. Let us know what you think of this new cadence. And here's a gentle reminder that this blog is fully open-source, so if you spot a typo, an error, a broken link, or have any other feedback, please feel free to file it in our blog.swiftwasm.org
GitHub repository.
We would like to welcome @yonihemi to the SwiftWasm team who joined us in the beginning of October. After the previous contributions he made to carton
it made perfect sense to expand our team. As always, we invite everyone to contribute to any of our repositories, and it doesn't require much prior experience with SwiftWasm if any at all. Bug fixes, feature additions, improved documentation and related changes are very much appreciated and allow our ecosystem to grow even more!
Our documentation was restructured and updated, and is now hosted on the book.swiftwasm.org
domain. Please file all feedback in the swiftwasm-book
repository on GitHub, which hosts its source code.
JavaScriptKit had a few important updates in October so far. Most importantly, now that PR #91 by @kateinoigakukun was merged, JavaScriptKit no longer uses unsafe flags in its Package.swift
. The use of unsafe flags was a big problem for us, as it breaks dependency resolution due to strict checks that SwiftPM applies. If any package in your dependency tree contains unsafe flags, you can no longer depend on its semantic version, or a semantic version of any other package that depends on it.
So far we were able to work around that with a hardcoded check for JavaScriptKit in our fork of SwiftPM. This was obviously a very ugly hack, but the biggest downside of that approach was that you couldn't depend on any package that had a semantic version dependency on JavaScriptKit in upstream Swift toolchains. That meant that libraries like Tokamak could not be built for macOS or Linux. And while the WebAssembly DOM renderer in Tokamak is the most useful module right now, this prevented static HTML rendering from working on macOS and Linux.
Another issue we had with JavaScriptKit is the naming of JSValueConstructible
and JSValueConvertible
protocols. These protocols are used for conversions between JSValue
references and arbitrary Swift values. In practice it wasn't always clear which of these protocols was responsible for a specific conversion. After some deliberation, these were renamed to ConstructibleFromJSValue
and ConvertibleToJSValue
respectively in #88.
A proposal PR was submitted by @kateinoigakukun to enable unsafe force unwrapping of dynamic member properties in JavaScript by default. That is, it would allow this
let document = JSObject.global.document
+let foundDivs = document.getElementsByTagName("div")
+
in addition to the currently available explicit style with force unwrapping:
let document = JSObject.global.document.object!
+let foundDivs = document.getElementsByTagName!("div").object!
+
The key thing to note is that the first option is still dynamically typed and these options are equivalent in their behavior. If you address a missing property on your JavaScript object with this API, your SwiftWasm app will crash. One possible reasoning for this change is that this would follow the approach of PythonKit and Swift for TensorFlow, and improve readability and ease of use for newcomers. We encourage you to voice your opinion in PR comments to give us more feedback on this proposal.
An issue was raised by @yonihemi this week on our JavaScriptKit repository about i64
Wasm function return type support in Safari. The reason for it is that Safari is the only major browser that doesn't support Wasm i64
to BigInt
conversion. Unfortunately, there are many APIs that require this conversion to work, and it's unclear yet if this can be polyfilled on the JavaScript side at all. Currently it looks like we need to apply some transformations to binaries produced by SwiftWasm to resolve this issue, but it remains to be seen how well that would work in practice.
Tokamak didn't see major updates recently, but we've received some important bug reports during the last few weeks. Firstly, there's an edge case with Picker
views that use \.self
as an identifier keypath. Secondly, Toggle
binding is not reset after its value changes outside of the view. Many thanks to @rbartolome for the extensive testing he's given and for reporting these issues!
In the first half of October @yonihemi submitted two important quality-of-life improvements to carton
:
There's also an open "Pretty print diagnostics" PR #112 submitted by @carson-katri. It does some magic with diagnostic messages emitted by the Swift compiler, highlights relevant lines of code and formats all of it nicely. You can check out a preview on this screenshot:
Not much upstreaming work happened in October yet, but there was some progress in adding cross-compilation support to SourceKit-LSP. We are also preparing a 5.3 SwiftWasm snapshot with this patch, which will enable this new --destination
option on SourceKit-LSP. When that works, we want carton
to infer a value for this option and launch it automatically for you when needed. This is all to make auto-complete work correctly for your SwiftWasm apps and libraries in VSCode or any other LSP-supporting editor or IDE.
Most of the work in preparation for the 5.3.0 release of SwiftWasm has been done. Now that it's possible to build JavaScriptKit without unsafe flags, and with IndexStoreDB and SourceKit-LSP shipping with the latest 5.3.0 snapshots, only the last round of testing is needed before tagging a release candidate. The rest of our work on the SwiftWasm toolchain and SDK was mostly related to fixing a build breakage caused by updates to GitHub Actions runner images and resolving conflicts with upstream code.
A lot of the progress wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on the sponsorship pages of Carson Katri, Yuta Saito and Max Desiatov.
Thanks for reading! 👋
Published on
@hassan-shahbazi wrote a 3 part guide about his experience when integrating SwiftWasm apps within Go apps through Wasmer. He also published example code accompanying the articles on GitHub. It's a great introduction to SwiftWasm that doesn't assume much prior knowledge, and could be useful if you'd like to integrate binaries produced by SwiftWasm in a host application.
@johngarrett published an interactive "Swift, Wasm, and Algorithms" documentation page. It is a demo of the recently released Swift Algorithms package where you can tweak parameters for some of the functions and observe results directly in the browser. Not all of the functions are fully interactive now, but it's a great proof of concept for interactive documentation websites one could build with SwiftWasm. Its source code is available on GitHub.
Two new sections were added to the SwiftWasm book that clarify limitations of Foundation, and recommended ways to use XCTest with the SwiftWasm SDK.
@kateinoigakukun published a pure Swift implementation of a transformer for Wasm binaries. This resolves the issue with i64
to BigInt
incompatibility in Safari, as we can now integrate an appropriate transformation into our build pipeline in carton
. The WasmTransformer
library is still at an early stage, but it shows that Swift is suitable for low-level code just as well as C/C++ or Rust.
carton
In addition to the WasmTransfomer integration mentioned above, carton test
now passes the --enable-test-discovery
flag to swift test
by default, which means that you no longer need to maintain LinuxMain.swift
and XCTestManifests.swift
files in your test suites.
A Dockerfile
was added to the carton
repository, and you can now run carton
in a Docker container, which also has the toolchain and other dependencies preinstalled. You can pull the Docker image with a simple command:
docker pull ghcr.io/swiftwasm/carton:latest
+
Additionally, carton
gained support for Ubuntu 20.04, and now also has a CI job to test compatibility with it during development. Similarly, a CI job for macOS Big Sur on Intel platforms was added as soon as GitHub Actions started providing appropriate CI images.
After these changes were merged carton
0.7 was released and is now available via Homebrew on macOS.
After the release, @carson-katri merged a PR that greatly improves command-line experience with carton test
. It builds on his previous work on carton dev
with compiler diagnostics parsing and error highlighting. With this new change XCTest output is also parsed, reformatted, and highlighted in a nice summary view.
Thanks to the fact that carton
is now available in a Docker image, it can now be used in our swiftwasm-action
, which previously only contained the plain SwiftWasm toolchain without any additional tools. This action now invokes carton test
by default on a given repository during a GitHub Actions run, but you can customize it and call any other command. For example, you could run carton bundle
with swiftwasm-action
, and then use the peaceiris/actions-gh-pages
step to deploy the resulting bundle to GitHub Pages.
JavaScriptKit 0.8.0 has been released. As mentioned in our previous issue, it introduces a few enhancements and deprecations, and is a recommended upgrade for all users.
@Cosmo pointed out that SwiftUI apps should change almost the whole palette when switching between color schemes. As he discovered when working on his OpenSwiftUI and SwiftUIEmbedded projects, the implementation of the Color
type is much more subtle than we originally anticipated. This was resolved by @carson-katri in #291 and is now available in the main
branch. The plan is to merge a few more changes and bugfixes, and to tag a new release of Tokamak soon after that.
@owenv merged a PR to the Swift Driver project implementing WebAssembly toolchain support. This mirrors our existing C++ implementation in the legacy driver, and it's great that the new parts of the Swift compiler rewritten in Swift are going to support WebAssembly too. While Swift Driver isn't enabled in any toolchain by default, we're definitely going to enable it at some point in the future as soon as it seems to be stable enough for us.
@kateinoigakukun submitted a PR to SwiftPM that propagates the -static-stdlib
flag correctly to the compiler driver. After it was merged, we were able to remove a bit of code that generated SwiftPM destination files to ensure correct linking, and this is no longer needed thanks to the upstream changes.
@MaxDesiatov merged a PR to Swift TSC that adds .wasm
file extension to WebAssembly binaries produced by SwiftPM. This extension was previously missing, which didn't make it obvious enough that these binaries can't be run without passing them to an appropriate WebAssembly host.
In preparation for the 5.3.0 release of SwiftWasm, our macOS archives are now distributed as signed .pkg
installers. Also need to mention that the toolchain archive is now available for Ubuntu 20.04, and all archive files now have consistent naming that includes the full OS name and CPU architecture. This will make it much easier for us to distribute ARM64 builds and builds for other Linux distributions in the future.
Another change to be included in 5.3 snapshots would add .wasm
file extension to binaries reflecting aforementioned upstream PRs.
Additionally, we found that it's currently not possible to build C++ code that includes certain headers with SwiftWasm 5.3 snapshots. As some Swift libraries do have C++ targets as their dependencies, it would be great if this is fixed before SwiftWasm 5.3.0 is tagged.
We'll be using latest 5.3 snapshots in our apps and libraries for some time, and will tag 5.3.0 when we have enough confidence there are no major issues.
The wasm-DEVELOPMENT-SNAPSHOT
archives will continue to be tagged on a regular basis to serve as a preview of the next version of SwiftWasm, but are not recommended for general use.
A lot of the progress wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on the sponsorship pages of Carson Katri, Yuta Saito and Max Desiatov.
Thanks for reading! 👋
Published on
As you may have seen in our previous post, we've published our first stable release recently. Shortly after that, @flavio reported an issue with JSONDecoder
. Following an investigation by @kateinoigakukun into the root cause of the issue, we've published SwiftWasm 5.3.1, which also included updates from the upstream 5.3.1 patch release.
(If you're interested in technical details, the JSONDecoder
issue was caused by a peculiar assumption about memory layout in Swift runtime, which wasn't applicable to WebAssembly's linear memory. Check the PR diff for more details.)
A major update since the latest 0.8.0 release of JavaScriptKit is newly added support for throwing functions developed by @kateinoigakukun. It required an update to the JavaScript runtime part, but was an additive change to the Swift API. As we try to publish releases regularly, new 0.9.0 release was tagged that includes this feature.
A PR with support for Asyncify transformation was created by @yonihemi. It allows calling asynchronous JavaScript APIs with Swift code that looks as plain synchronous code, but through proper suspension that doesn't block browser rendering. The PR has some implications on how we build things, especially as it requires a specific optimizer transformation. It is still in the draft stage, and you're welcome to contribute to the ongoing discussion.
We still use a fork of OpenCombine in Tokamak due to our custom implementation of the ObservableObject
protocol. In addition to that, our fork also contained some changes to the package manifest to make it build with SwiftWasm, but they made it incompatible with non-Wasm platforms. This issue was resolved in the upstream OpenCombine repository, which reduced the amount of customizations we apply, and brings us closer to using the upstream repository as is.
With progress on OpenCombine, it was time to publish the first version of OpenCombineJS. Its code didn't change recently, but parts of it were used in Tokamak already, which gave us confidence that it was reliable enough to be released in a separate library for wider use. It currently doesn't contain much code, but this basic functionality should be enough for basic integration of JavaScriptKit types and OpenCombine.
Following the 0.5.0 release, which added support for the latest carton
, we published a small 0.5.1 patch with support for editing Tokamak projects in Xcode with working autocomplete. Not long after that an important bugfix landed in 0.5.2, which fixed an issue with display order of updated views in the DOM renderer. A few weeks later another bugfix release was published as 0.5.3. In this update Tokamak now internally relies on the aforementioned OpenCombineJS library instead of providing its own JSScheduler
type conforming to Combine's Scheduler
. More importantly, it fixes a bug with Toggle
not being updated after resetting it from a binding.
@kateinoigakukun implemented a stripCustomSections
transformation in the WasmTransformer
library. According to the spec, data in custom sections should not contribute to observed behavior of a given binary. In the case of binaries produced by SwiftWasm, custom sections contain debugging information that can now be stripped with
WasmTransformer
.
carton
Previously, custom sections were stripped to reduce final binary size as a build step in `carton bundle with the
wasm-strip` utility from WABT. Thanks to the new transformation in WasmTransformer
, WABT is no longer needed as a dependency of carton
, which makes installation for our end users simpler and faster.
Initial support for presenting crash stack traces directly in carton
has been completed, starting with Firefox support. Support for more browsers will be added in separate PRs.
There was also work on file downloader cleanup, support for browser testing, and simpler URLs for main bundle resources. As soon as these are merged, a new version of carton
will be tagged that will use the latest 5.3.1 release of SwiftWasm.
A lot of the progress wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on the sponsorship pages of Carson Katri, Yuta Saito and Max Desiatov.
Thanks for reading! 👋
Published on
Happy New Year everyone! Here's a digest of what happened with SwiftWasm in December of 2020, published with a slight delay (it's 2021 already after all 😅).
One thing we forgot to mention in our November update is that the SwiftWasm community now has its own Discord server. In case you prefer Slack to Discord, we recommend you to join the #webassembly
channel in the SwiftPM Slack workspace.
In December we saw a lot of projects built with SwiftWasm shared by the community. Here a few most noteworthy:
Ever wanted to contribute to SwiftWasm projects, but unsure where to start? Here's a list of issues that could be suitable for beginners:
carton test
--enable-test-discovery
is now deprecated--host
option to carton dev
and carton test
We're working on tracking down all the possible edge cases when porting code from other platforms in the SwiftWasm book. Previously we were asked how to port code that depends on the Darwin
module on Apple platforms or Glibc
on Linux. We recommend using the WASILibc
module, which obviously somewhat differs from libc on other platforms. We've added a corresponding note clarifying this to the book.
As the Swift team already announced the release process for the 5.4 version, we started preparing our corresponding SwiftWasm 5.4 release. The swiftwasm-release/5.4
branch in our fork now tracks the upstream release/5.4
branch, as we plan to tag our own 5.4.0 later this year.
Additionally, we made sure that the fork of our toolchain can be compiled on Apple Silicon Macs. While GitHub Actions doesn't provide CI agents for the M1 architecture, the SwiftWasm toolchain can be built locally for Apple Silicon, and we hope to provide a prebuilt distribution archive for it in some future release.
@kateinoigakukun enabled experimental concurrency support in SwiftWasm and fixed several issues that previously prevented us from enabling async
/await
in development snapshots. Currently, starting with swift-wasm-DEVELOPMENT-SNAPSHOT-2021-01-02-a, the toolchain only supports a single-threaded task executor. This executor is suitable for usage in standalone WASI hosts such as Wasmer or Wasmtime. Unfortunately, it blocks the JavaScript event loop until all jobs are completed, and is unable to run any jobs created after the first event loop cycle. While this makes it unsuitable for JavaScript environments, we were able to work around that in JavaScriptKit as discussed in the next section.
@kateinoigakukun started implementing a Swift concurrency task executor integrated with the JavaScript event loop. There are still several issues, but it's working well as a proof of concept. This experimental API allows us to utilize async
/await
in SwiftWasm apps for browsers and Node.js like this:
import JavaScriptEventLoop
+import JavaScriptKit
+
+JavaScriptEventLoop.install()
+let fetch = JSObject.global.fetch.function!.async
+
+func printZen() async {
+ let result = try! await fetch("https://api.github.com/zen").object!
+ let text = try! await result.asyncing.text!()
+ print(text)
+}
+
+JavaScriptEventLoop.runAsync {
+ await printZen()
+}
+
@kateinoigakukun published a Swift WebAssembly runtime package powered by the WebAssembly Micro Runtime project (WAMR). This allows us to remove Wasmer dependency from carton
and embed the WebAssembly runtime in the carton
binary for use in commands such as carton test
.
We were also able to test this package on Apple Silicon and submit a PR upstream to make it work.
Our long-term goal is to make DOMKit the recommended library for type-safe interactions with Web APIs in SwiftWasm. While it's still at an early stage, we've updated it to JavaScriptKit 0.9 and added support for globalThis
. In a separate PR we've cleaned up unused code and fixed an event handlers crash.
With enough changes to warrant a new release, we've published Tokamak 0.6.0, which introduced support for the Image
view loading images bundled as SwiftPM resources, implemented by @j-f1. It also adds the PreferenceKey
protocol and related modifiers. developed by @carson-katri.
Since then we've also added the PreviewProvider
protocol, an implementation of TextEditor
, and updated our example code in README.md
for script injection. Additionally, a contribution from David Hunt added missing typealiases to TokamakDOM that should improve compatibility with SwiftUI, while Jed Fox removed redundant path
element from SVG output.
carton
We'd like to welcome @thecb4, who is the latest addition to the carton
maintainers team! Thanks to his work, project targets were restructured for better testability, and now test
, dev
, and bundle
commands are covered with end-to-end tests.
There's ongoing work to integrate the WAMR package mentioned above with the carton test
command. Also, carton
now correctly handles system target dependencies in Package.swift
.
On top of that, stack traces from Chrome and Safari are now supported in carton dev
with proper symbol demangling, thanks to the work by @j-f1. Additionally, @yonihemi submitted a PR which integrates carton
with libSwiftPM allowing us to reuse its model types.
Most of these changes were included in 0.9.0 and 0.9.1 releases published in December.
webidl2swift
webidl2swift
is the foundation on which our DOMKit framework is built. Web API across all browsers is specified in the Web IDL format, which can then be parsed to generate type-safe bindings in Swift. The parser doesn't support all IDL files out there yet, but we've updated dependencies and updated the code generator to certain JavaScriptKit types that previously were deprecated.
There were a few changes to the WasmTransformer package, which we use in carton
and intend to use in a few other dev tools. Specifically, we've generalized section info parsing across different transformers, implemented a basic section size profiler, and made the TypeSection
type public to make it easier to analyze sections of WebAssembly binaries.
We're excited to announce our new developer tool enabled by WasmTransformer. Gravity is a binary code size profiler for WebAssembly built with WasmTransformer, SwiftUI, and TCA. It's an application for macOS that allows you to open a WebAssembly binary and view the size of different sections. Contents of some of the sections is also parsed for further analysis.
A lot of our progress with SwiftWasm wouldn't be possible without payments from our GitHub Sponsors. Their contribution is deeply appreciated and allows us to spend more time on SwiftWasm projects. You can see the list of sponsors and make your contribution on our SwiftWasm organization sponsorship page, or personal sponsorship pages of Carson Katri, Yuta Saito and Max Desiatov.
Thanks for reading! 👋