Since official support for Wasm in Swift 6.2 was announced at WWDC this year, Swift contributors have done a huge amount of work. To provide better visibility and to track progress, here’s a list of notable changes:
-
Breaking change: wasm32-unknown-wasi
triple wasm renamed to wasm32-unknown-wasip1
. The p1
suffix explicitly indicates WASI Preview 1, which helps distinguish it from the newer WASI Preview 2 (wasip2
) and provides clarity about which version of the WASI specification is being targeted.
Users will need to update build invocations that relied on --triple
option. However, the underlying functionality remains identical; only the triple identifier changed. Users that relied on Swift SDK IDs passed to --swift-sdk
are not impacted.
-
Embedded Swift concurrency is now enabled for CLI executables (compatible with swift run
) built with main
development snapshots of the Swift toolchain. Some async
stdlib functions, such as Task.sleep
are not available yet.
-
Embedded Swift concurrency can also be used in browser applications that utilize JavaScriptEventLoop
from the JavaScriptKit
library, as demonstrated in the WebGPUDemo
example package.
-
swiftlang/github-workflows
now support Swift SDKs for Wasm controlled by enable_wasm_sdk_build
and enable_embedded_wasm_sdk_build
configuration settings. This enabled Wasm CI jobs merged or in review now for multiple libraries: swift-algorithms, swift-async-algorithms, swift-argument-parser, swift-atomics, swift-collections, swift-foundation, swift-crypto, swift-log, swift-nio, swift-numerics, swift-syntax, and swift-system.
-
Wasm plugin has been added to upstream LLDB (soon to be available in Swift LLVM 21 rebranch) in a series of PRs: #150143, #151445, #151056, #151010.
-
Swift SDK for Wasm now includes Foundation in both main
and 6.2 development snapshots. Note that Foundation isn’t supported in Embedded Swift yet.
-
WasmKit 0.1.6 added Android support and dropped Swift 5.9 support.
-
JavaScriptKit had multiple releases in the 0.31...0.35 range with numerous changes:
-
Added JSClosure
APIs to support specifying TaskExecutor
and TaskPriority
in #383;
-
Added JavaScriptFoundationCompat
module to provide utilities to interact Foundation types in #378;
-
Improved support for Embedded Swift in #369 and #390;
-
Multiple improvements to BridgeJS: new package plugin for bidirectional JavaScript/TypeScript and Swift interop.
-
Created a public Swift for Wasm GitHub project board on the swiftlang
GitHub organization.
-
Added DOMRefTypes
example to swift-for-wasm-examples
, showing advanced use of Wasm reference types via C interop.
-
Fixed “import WASILibc
is unavailable in Embedded Swift for WASI”.
-
Fixed incorrect va_list
C interop behavior when using WASI-libc.
Surely I missed a few changes in this list unintentionally, so please feel free to post what you found notable in this thread. Many thanks to all of the contributors pushing the ecosystem forward!
54 Likes
This is very cool. I really need to try out some WASM stuff soon if just to play with it!
1 Like
Are there any plans for Carton?
We are soft-deprecating Carton in favor of swift package js
SwiftPM Package Plugin provided by JavaScriptKit, which just generates an ES Module + .wasm file. You can still use Carton for now, but I no longer have any further plans to invest in Carton for now.
4 Likes
I see. What are the plans for the debugging features?
We actually added enhanced Swift support in the Wasm debugging extension for Chrome DevTools early this year: Debugging - Swift and WebAssembly
5 Likes
I see. So that feature wasn’t necessarily required to be used with Carton. I apologize. I feel like I have been updating and changing how I build my project that I have lost track of where all the parts come into play. I have stayed with 5.10 so I can keep using carton. But I gotta move to 6.1+, so now I’m trying to move to whatever the newest way to do things is. I just finished building a new Ubuntu VM to test. The project compiled fine using the instructions form the page your provided.
Is there a mechanism to run 'wasm-opt’ after it is built?
Yes, swift package js -c release
automatically applies wasm-opt after the build if the tool is installed.
I see. So the tool is installed. But the binary is at 120mb (should be like 20mb after wasm-opt). Is the stripped file being moved somewhere else? I guess, what I mean is there a folder like “Bundle” that is being created somewhere?
- Hmm, if you build with release configuration, debug symbols should be stripped unless you explicitly pass
--debug-info-format
option. Can you share your build command?
- The "Bundle" directory is generated under
.build/plugins/PackageToJS/outputs/Package
by default. If you pass --output
option with --allow-writing-to-package-directory
plugin option, you can keep the existing directory layout:
$ swift package --swift-sdk "${SWIFT_SDK_ID}" -c release plugin --allow-writing-to-package-directory js --output ./Bundle
1 Like
I was just building with
swift package --swift-sdk 6.1-RELEASE-wasm32-unknown-wasi js --use-cdn
I used your suggested command (which is a life saver thank you!)
$ swift package --swift-sdk 6.1-RELEASE-wasm32-unknown-wasi -c release plugin --allow-writing-to-package-directory js --output ./Bundle
The .wasm file is now 50mb. Still not the almost 20mb it was when building with 5.10 and Carton.
Is there an optimization option that I could pass?
The major binary size difference in the recent versions is ICU data. Recent Foundation brought full-featured ICU data into our binary, so you might be able to reduce the size into what we had before by replacing the data with slimmed version: GitHub - GoodNotes/swift-icudata-slim: A slimmed-down version of ICU for Swift
I did not realize at all that the increase in ICU data would cause an approaching 30MB (I fathom that some of the size increase is from other stuff too?) . I suppose it is not awful. The site will just take about twice as long to load, which given the niche-ness of it that is ok.
Lastly is there an argument to get the index.html
file to copy into the ./Bundle folder? Other than that (which I can definitely do myself), this looks like it is going to be mostly a good replacement.
I think you actually don't need to copy index.html to ./Bundle. Instead, you can:
$ mkdir dist
$ cat <<EOS > dist/index.html
<!DOCTYPE html>
<html>
<body>
<script type="module">
import { init } from "./Bundle/index.js";
init();
</script>
</body>
</html>
EOS
$ swift package js --output ./dist/Bundle
$ echo "./dist/Bundle" >> .gitignore
$ # Serve ./dist by your HTTP server
1 Like
So I am a little confused, when I do --wasm-optimizations none
with Carton on 5.10, the resulting binary is only about 32MB (with optimization it is about 20MB), but when I run it using the new method under 6.1 the resulting binary is larger than when there is no optimization at all on the old version.
I am wondering if something else is happening here that I am either skipping or missing. Like maybe certain unused functions are not being stripped?
Surly it isn't all ICU tables? Is it?
If you can provide me a reproducible example, I can take a closer look 