anyway, getting this thread back on track…
the next thing i am going to aim to do today is:
of course before i build an app i first need to come up with an idea for an app.
brainstorming an app
now i work a lot with MongoDB lately, and something i’ve complained about to anyone else who will listen is that is no online BSON inspector known to Google.
if you install the MongoDB developer tools, you can convert the BSON to Extended JSON, and look at the JSON, but that only really works for very small BSON. for comparison, the BSON on Swiftinit can be many megabytes in size, and contains a lot of BSON-specific structures that are not particularly readable when converted to JSON.
i could write a web app in JavaScript, but parsing BSON with JavaScript is probably going to be slow, and i want this to work with giant BSON blobs like the ones on Swiftinit.
i could parse the BSON server-side, and return the rendered HTML to the user that way, but then i would have to stand up a server which would then become the bottleneck. so this sounds like the type of problem that Swift on WebAssembly could really help with.
setting up my project
it sounds like Swift on WebAssembly requires a nightly toolchain to get binaries of a reasonable size, so i add a .swift-version
to my project, and i figure that since i have already resigned to using a nightly toolchain, i might as well use the most recent nightly toolchain available, so i replace wasm-DEVELOPMENT-SNAPSHOT-2024-10-27-a
from the example project with wasm-6.1-SNAPSHOT-2025-01-18-a
, which is the most recent one they have listed on GitHub.
i need to use JavaScriptKit to do anything that involves DOM, so my Package.swift looks like this, like the example:
// swift-tools-version:6.0
import PackageDescription
let package:Package = .init(name: "test",
products: [
],
dependencies: [
// .package(url: "https://github.com/swiftwasm/carton", from: "1.1.3"),
.package(path: "../carton"),
.package(url: "https://github.com/swiftwasm/JavaScriptKit", from: "0.21.0"),
],
targets: [
.executableTarget(name: "BSONViewer",
dependencies: [
.product(name: "JavaScriptKit", package: "JavaScriptKit"),
]),
])
and in BSONViewer
, i’ve kept the placeholder code:
import JavaScriptKit
let document = JSObject.global.document
var div = document.createElement("div")
div.innerHTML = "Hi Barbie!"
_ = document.body.appendChild(div)
$ swift run carton dev --custom-index-page Web/index.html
i get a bunch of Sendable
noise, like with the older toolchain, and i also get these, which sound benign at least.
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/lib_FoundationCollections.a: archive member '_FoundationCollections.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/libFoundation.a: archive member 'Foundation.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/libFoundationEssentials.a: archive member 'FoundationEssentials.autolink' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/lib/swift_static/wasi/libFoundationInternationalization.a: archive member 'FoundationInternationalization.autolink' is neither Wasm object file nor LLVM bitcode
but it Does Work, and i can see that i really can manipulate DOM with JavaScriptKit, which is cool!
do i really need Tokamak UI?
i barely know anything about JavaScriptKit, but at first glance, it does not include an HTML renderer, which is perfect because it would have really sucked if JavaScriptKit forced me to use a particular HTML rendering framework.
i’ve heard about Tokamak UI, but i also know from this thread that @austintatious is doing Cool Stuff with Swift on WebAssembly without using Tokamak at all, so i am very curious: do i really need Tokamak to do Serious WebAssembly?
i take a look at its GitHub README, which is a pretty good README as far as GitHub READMEs go, because it tells me all of the important information i need to know about the framework without going into excessive detail.
-
it tells me that it has a lot of current users (66 on the Discord!), which makes me want to use the framework.
-
it tells me that it is incomplete, which does not make me want to use the framework.
-
it tells me that it’s designed to mimic SwiftUI, which i guess would be a huge plus if i were porting a SwiftUI app, but i am not doing that, so that doesn’t apply to me.
so i imagine the algorithm for choosing Tokamak is: “if you are invested in SwiftUI, then Definitely Yes; otherwise, Explore Your Alternatives.”
i scroll down a bit more, and i see that Tokamak does HTML rendering. that confirms that i was hoping for — JavaScriptKit does JavaScript interop, and Tokamak does HTML rendering (along with some “modern” front-end reacty stuff i don’t need just yet.) so this is Very Good. the Layering Makes Sense. neat!
can i bring my own HTML renderer?
the HTML example on the Tokamak README looks like this:
struct SVGCircle: View {
var body: some View {
HTML("svg", ["width": "100", "height": "100"]) {
HTML("circle", [
"cx": "50", "cy": "50", "r": "40",
"stroke": "green", "stroke-width": "4", "fill": "yellow",
])
}
}
}
not bad, but i would much rather use swift-dom.
the first thing i notice when i go back to my code is that sourcekit-lsp is not online. but i had already been warned about this, and apparently you have to build the project for the host to enable syntax highlighting.
this is annoying but not the worst thing in the world. let’s make some HTML!
let html:HTML = .init
{
$0[.svg, { $0.width = "100" ; $0.height = "100" }]
{
$0[.circle]
{
$0.cx = "50"
$0.cy = "50"
$0.r = "40"
$0.stroke = "green"
$0.stroke_width = "4"
$0.fill = "yellow"
}
}
}
the first thing i try to do is render this HTML to a string, since that’s what it looked like i was doing in the example code. but that doesn’t work.
div.innerHTML = "\(html)"
// Cannot assign value of type 'String' to type 'JSValue'
okay, so we weren’t actually assigning a string to innerHTML
, it was going through some kind of ExpressibleByStringLiteral
sugar that doesn’t support string interpolations. code completion leads me to this instead:
div.innerHTML = .string("\(html)")
i suspect JavaScriptKit cannot bridge a native Swift String
to JavaScript, so there is probably a buffer copy going on here. HTML
stores its content as a plain old [UInt8]
, and provides it through HTML.utf8
so i wonder if there is a way to copy directly to a JavaScript string without converting to String
in between. but that is a problem for another day.
previewing with carton
i re-run carton dev
and reload the browser tab and… nothing loads
in the VSCode terminal, i see this:
open browser failed: Executable xdg-open not found in PATHINFO [org.swiftwasm.carton.dev-server] GET /
INFO [org.swiftwasm.carton.dev-server] GET /dev.js
INFO [org.swiftwasm.carton.dev-server] GET /main.wasm
INFO [org.swiftwasm.carton.dev-server] GET /favicon.ico
INFO [org.swiftwasm.carton.dev-server] GET /JavaScriptKit_JavaScriptKit.resources/Runtime/index.mjs
INFO [org.swiftwasm.carton.dev-server] GET /
INFO [org.swiftwasm.carton.dev-server] GET /dev.js
INFO [org.swiftwasm.carton.dev-server] GET /main.wasm
INFO [org.swiftwasm.carton.dev-server] GET /favicon.ico
INFO [org.swiftwasm.carton.dev-server] GET /JavaScriptKit_JavaScriptKit.resources/Runtime/index.mjs
An error occurred, here's a stack trace for it:
An error occurred, here's a stack trace for it:
i reload the page, and this time it loads successfully. the circle is there!
i would brush off the failed page load as a one-time thing, but as i use carton
more and more, i notice it continuing to happen. moreover, sometimes the WebAssembly just doesn’t load at all while Firefox says it’s “transferring data”, forever. it almost feels like there is some kind of browser session state that carton
has, because it will only start loading when i open the URL in a Private Browsing Window.
so from now on, i just use Private Browsing to preview WebAssembly with carton
.
implementing drag-and-drop
let’s try and add some event handlers to that div
!
this is Pretty Tough. JavaScriptKit
relies almost entirely on @dynamicMemberLookup
, which means no code completion.
the API is not intuitive. this does not compile:
div.addEventListener("dragover")
{
$0.preventDefault()
}
// error: Extra trailing closure passed in call
the diagnostic doesn’t give me any leads at all. that function is @dynamicCallable
, so there is no signature when i hover over it in VSCode. i jump back over @svanimpe ’s examples, and am lucky enough to come across connect-four/Front-end/Sources/WebUI.swift
which has an example of how to call addEventListener
:
thank you Steven! now i have this:
_ = div.addEventListener("dragover", JSClosure.init
{
$0[0].preventDefault()
})
printing things to the console
i then tried printing a message to the terminal
_ = div.addEventListener("dragover", JSClosure.init
{
print("DRAGGED")
$0[0].preventDefault()
})
that didn’t compile, which i didn’t understand at first, because i thought this was a Void
-returning function, but it turns out that preventDefault
returns a JSValue
, which was being used as the closure return type because of Swift’s implicit return syntax. (please, let us not add any more implicit syntax to the language!)
it seems JavaScript does not have Void
functions, so we must explicitly return .undefined
.
weird at first, but it makes sense and you get used to it over time.
_ = div.addEventListener("dragover", JSClosure.init
{
print("DRAGGED")
_ = $0[0].preventDefault()
return .undefined
})
funny enough, Swift WebAssembly is smart enough to connect Swift.print
to console.log
, so the print actually worked, even though i didn’t really expect it to. neat!
the drop handler
next up is the drop handler!
JavaScriptKit is really hard to use. it has its patterns, which make sense after a while, but it was very unintuitive as someone Completely New to the framework. i often found myself tunneling through the source code for JavaScriptKit to figure out how to do basic things with this library.
_ = div.addEventListener("drop", JSClosure.init
{
print("DROPPED")
let event:JSValue = $0[0]
_ = event.preventDefault()
guard
case .object(let data) = event.dataTransfer
else
{
return .undefined
}
print(data)
print(data.files)
guard data.files.length == 1
else
{
print("Need exactly one file")
return .undefined
}
return .undefined
})
one thing that stumped me for a really long time was how to call functions.
guard
case .object(let file) = data.files[0],
case .object(let promise) = file.bytes()
else
{
print("Not a file")
return .undefined
}
Value of optional type '((any ConvertibleToJSValue...) -> JSValue)?'
must be unwrapped to a value of type
'(any ConvertibleToJSValue...) -> JSValue'
App.swift(55, 38): Coalesce using '??' to provide a default when the optional value contains 'nil'
App.swift(55, 38): Force-unwrap using '!' to abort execution if the optional value contains 'nil'
…huh?
as it turns out, file.bytes
is not a real instance method, it’s a functor thing you have to unwrap with optional chaining, even though this is not required anywhere else.
- case .object(let promise) = file.bytes()
+ case .object(let promise)? = file.bytes?()
🫨 typechecking with JavaScriptKit
typechecking with JavaScriptKit is really, really confusing.
the next few lines i wrote were this:
promise.then?(JSClosure.init
{
guard case .object(let typedArray) = $0
else
{
print("Not bytes")
return .undefined
}
return .undefined
})
that suddenly caused the code i had written 30 lines above to stop type checking!
/swift/wasm-test/Sources/BSONViewer/App.swift:40:17: error: value of tuple type '()' has no member 'undefined'
38 | else
39 | {
40 | return .undefined
| `- error: value of tuple type '()' has no member 'undefined'
41 | }
…what? value of tuple type '()' has no member 'undefined'
?
of course, the actual problem was i had forgotten JSClosure
passes an array of arguments instead of a single argument.
promise.then?(JSClosure.init
{
- guard case .object(let typedArray) = $0
+ guard case .object(let typedArray) = $0[0]
but that had nothing to do with tuples having members undefined
, and it was in a completely different scope of the code.
i spent a lot of time trying to figure out what was going wrong here. i also spent some time trying to figure out how to convert a Uint8Array
to a [UInt8]
, but i suppose that is a less common use case.
let bytes:[UInt8] = JSTypedArray<UInt8>.init(
unsafelyWrapping: typedArray).withUnsafeBytes
{
[UInt8].init($0)
}
i learned how to do this by searching GitHub for 'Uint8Array'
and skimming the source code of JSTypedArray.swift
.
parsing BSON with Swift WebAssembly
okay, pretty cool! i can get raw bytes from drag and drop files with WebAssembly! now let’s parse some BSON!
i hook up swift-bson to Package.swift, and bind the array to BSON.Document
in the app code.
.package(url: "https://github.com/tayloraswift/swift-bson", from: "1.0.0"),
.executableTarget(name: "BSONViewer",
dependencies: [
.product(name: "JavaScriptKit", package: "JavaScriptKit"),
.product(name: "BSON", package: "swift-bson"),
.product(name: "HTML", package: "swift-dom"),
]),
let bson:BSON.Document = .init(bytes: bytes[...])
i build it on the host, so far so good!
$ swift build
Building for debugging...
/swift/wasm-test/Sources/BSONViewer/App.swift:78:13: warning: immutable value 'bson' was never used; consider replacing with '_' or removing it
76 | }
77 |
78 | let bson:BSON.Document = .init(bytes: bytes[...])
| `- warning: immutable value 'bson' was never used; consider replacing with '_' or removing it
79 |
80 | return .undefined
/swift/wasm-test/Sources/BSONViewer/App.swift:78:13: warning: immutable value 'bson' was never used; consider replacing with '_' or removing it
76 | }
77 |
78 | let bson:BSON.Document = .init(bytes: bytes[...])
| `- warning: immutable value 'bson' was never used; consider replacing with '_' or removing it
79 |
80 | return .undefined
[12/12] Linking BSONViewer
Build complete! (1.73s)
now let’s build for WebAssembly…
$ swift run carton dev --custom-index-page Web/index.html
Building for debugging...
[1/1] Write swift-version--75355AAB4E86B17C.txt
Build of product 'carton' complete! (0.76s)
- checking Swift compiler path: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/bin/swift
Inferring basic settings...
- swift executable: /home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/bin/swift
Swift version 6.1-dev (LLVM 38a3fc37c5f5e7a, Swift eedae18ae4df60a)
Target: x86_64-unknown-linux-gnu
Running "/home/ubuntu/.carton/sdk/wasm-6.1-SNAPSHOT-2025-01-18-a/usr/bin/swift" "package" "--triple" "wasm32-unknown-wasi" "--scratch-path" "/swift/wasm-test/.build/carton" "--disable-sandbox" "plugin" "carton-dev" "--custom-index-page" "Web/index.html" "--pid" "170487"
Building for debugging...
[1/1] Write swift-version-5F410D2014D93A3.txt
Build of product 'carton-frontend' complete! (1.09s)
Building "BSONViewer"
Building for debugging...
[0/16] Write sources
[8/22] Write swift-version-5F410D2014D93A3.txt
...
[175/207] Compiling BSONDecoding BSON.TracingDecoder.swift
error: compile command failed due to signal 6 (use -v to see invocation)
Failed to reconstruct type for $sSY_s8SendablepSS8RawValueSYRts_XPXmTD
Original type:
(existential_metatype_type thick
(protocol_composition_type
(parameterized_protocol_type
(base=protocol_type decl="Swift.(file).RawRepresentable")
(struct_type decl="Swift.(file).String"))
(protocol_type decl="Swift.(file).Sendable")))
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
Pass '-Xfrontend -disable-round-trip-debug-types' to disable this assertion.
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
Stack dump:
0. Program arguments: ...
1. Swift version 6.1-dev (LLVM 38a3fc37c5f5e7a, Swift eedae18ae4df60a)
2. Compiling with the current language version
3. While evaluating request IRGenRequest(IR Generation for file "/swift/wasm-test/.build/carton/checkouts/swift-bson/Sources/BSONDecoding/Decoding/BSON.KeyspaceError.swift")
4. While emitting IR SIL function "@$s7BSONABI4BSONO12BSONDecodingE13KeyspaceErrorV5spaceSY_s8SendablepSS8RawValueSYRts_XPXpvg".
for getter for space (at /swift/wasm-test/.build/carton/checkouts/swift-bson/Sources/BSONDecoding/Decoding/BSON.KeyspaceError.swift:15:13)
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0 swift-frontend 0x000060c2a8fd7157
1 swift-frontend 0x000060c2a8fd4d0e
2 swift-frontend 0x000060c2a8fd77fa
3 libc.so.6 0x0000733ce7045320
4 libc.so.6 0x0000733ce709eb1c pthread_kill + 284
5 libc.so.6 0x0000733ce704526e gsignal + 30
6 libc.so.6 0x0000733ce70288ff abort + 223
7 swift-frontend 0x000060c2a211f51e
8 swift-frontend 0x000060c2a211f8bd
9 swift-frontend 0x000060c2a21166a2
10 swift-frontend 0x000060c2a2117282
11 swift-frontend 0x000060c2a2134b45
12 swift-frontend 0x000060c2a2133f2f
13 swift-frontend 0x000060c2a1fd23ff
14 swift-frontend 0x000060c2a1e4ccc9
15 swift-frontend 0x000060c2a1ebde33
16 swift-frontend 0x000060c2a1ebdd89
17 swift-frontend 0x000060c2a1e56e8f
18 swift-frontend 0x000060c2a1e4f50e
19 swift-frontend 0x000060c2a19d6b79
20 swift-frontend 0x000060c2a19d2812
21 swift-frontend 0x000060c2a19d154b
22 swift-frontend 0x000060c2a19e1ff5
23 swift-frontend 0x000060c2a19d43f5
24 swift-frontend 0x000060c2a19d34ac
25 swift-frontend 0x000060c2a17ab803
26 libc.so.6 0x0000733ce702a1ca
27 libc.so.6 0x0000733ce702a28b __libc_start_main + 139
28 swift-frontend 0x000060c2a17aa885
well, we were always going to run into this sooner or later. kids, this is why we don’t use nightly toolchains!
marty, we have to go back!!!
okay, so wasm-6.1-SNAPSHOT-2025-01-18-a
was always going to be a gamble, and we can’t use 6.0.2-RELEASE
in production, but for curiosity’s sake, i at least want to know if my code does the thing i’m expecting it to.
so i switch my .swift-version
back to 6.0.2-RELEASE
. i add a couple lines to dump the BSON to the console:
let bson:BSON.Document = .init(bytes: bytes[...])
print(bytes.count)
print("\(bson)")
i drag and drop a random BSON file i had lying around, and boom! it shows up!
conclusions
we are so close. so close. i have learned how to run Swift Code that depends on Real Swift Libraries directly in Firefox. this is really cool!
but the binaries are quite large. they take a very long time to download, which severely limits their practical applications.
these problems can be mitigated in theory by using experimental Swift compiler features, but this fails when you try to use Swift on WebAssembly to build anything bigger than a minimal test project.
i am very interested in hearing from anyone using Swift on WebAssembly in production who has figured out a way to work around the frequent compiler crashes.