1581133241
В этом докладе вы узнаете про то, как устроен WebAssembly и почему именно таким образом. Спикер разберет виртуальную машину, ее возможности и ограничения, формат байткода, текущие реализации. Никаких «мы скачали emscripten и что-то там скомпилировалось и как-то там работает».
#WebAssembly #web-development
1581133241
В этом докладе вы узнаете про то, как устроен WebAssembly и почему именно таким образом. Спикер разберет виртуальную машину, ее возможности и ограничения, формат байткода, текущие реализации. Никаких «мы скачали emscripten и что-то там скомпилировалось и как-то там работает».
#WebAssembly #web-development
1668158040
Compile your Swift code to WebAssembly
This is the main repository for SwiftWasm toolchain and SDK. Please refer to the SwiftWasm book to get started, and to the awesome-swiftwasm
list for more links in the SwiftWasm ecosystem.
If you'd like to participate in the growing SwiftWasm community, you're very welcome to join our Discord server, or the #webassembly
channel in the SwiftPM Slack.
What follows below is README.md
of the upstream Swift project included verbatim. If you'd like to track the status of our builds, please refer to our GitHub Actions page.
Swift Programming Language
Architecture | Build | |
---|---|---|
macOS | x86_64 | |
Ubuntu 18.04 | x86_64 | |
Ubuntu 20.04 | x86_64 | |
Ubuntu 20.04 | AArch64 | |
Ubuntu 22.04 | x86_64 | |
Ubuntu 22.04 | AArch64 | |
CentOS 7 | x86_64 | |
Amazon Linux 2 | x86_64 | |
Amazon Linux 2 | AArch64 |
Swift Community-Hosted CI Platforms
OS | Architecture | Build |
---|---|---|
Ubuntu 20.04 | wasm32 | |
Android | ARMv7 | |
Android | AArch64 | |
Windows 2019 (VS 2017) | x86_64 | |
Windows 2019 (VS 2019) | x86_64 |
Swift is a high-performance system programming language. It has a clean and modern syntax, offers seamless access to existing C and Objective-C code and frameworks, and is memory safe by default.
Although inspired by Objective-C and many other languages, Swift is not itself a C-derived language. As a complete and independent language, Swift packages core features like flow control, data structures, and functions, with high-level constructs like objects, protocols, closures, and generics. Swift embraces modules, eliminating the need for headers and the code duplication they entail.
To learn more about the programming language, visit swift.org.
Contributions to Swift are welcomed and encouraged! Please see the Contributing to Swift guide.
To be a truly great community, Swift.org needs to welcome developers from all walks of life, with different backgrounds, and with a wide range of experience. A diverse and friendly community will have more great ideas, more unique perspectives, and produce more great code. We will work diligently to make the Swift community welcoming to everyone.
To give clarity of what is expected of our members, Swift has adopted the code of conduct defined by the Contributor Covenant. This document is used across many open source communities, and we think it articulates our values well. For more, see the Code of Conduct.
If you are interested in:
We also have an FAQ that answers common questions.
Swift toolchains are created using the script build-toolchain. This script is used by swift.org's CI to produce snapshots and can allow for one to locally reproduce such builds for development or distribution purposes. A typical invocation looks like the following:
$ ./swift/utils/build-toolchain $BUNDLE_PREFIX
where $BUNDLE_PREFIX
is a string that will be prepended to the build date to give the bundle identifier of the toolchain's Info.plist
. For instance, if $BUNDLE_PREFIX
was com.example
, the toolchain produced will have the bundle identifier com.example.YYYYMMDD
. It will be created in the directory you run the script with a filename of the form: swift-LOCAL-YYYY-MM-DD-a-osx.tar.gz
.
Beyond building the toolchain, build-toolchain
also supports the following (non-exhaustive) set of useful options:
--dry-run
: Perform a dry run build. This is off by default.--test
: Test the toolchain after it has been compiled. This is off by default.--distcc
: Use distcc to speed up the build by distributing the C++ part of the swift build. This is off by default.--sccache
: Use sccache to speed up subsequent builds of the compiler by caching more C++ build artifacts. This is off by default.More options may be added over time. Please pass --help
to build-toolchain
to see the full set of options.
On macOS if one wants to install such a toolchain into Xcode:
Untar and copy the toolchain to one of /Library/Developer/Toolchains/
or ~/Library/Developer/Toolchains/
. E.x.:
$ sudo tar -xzf swift-LOCAL-YYYY-MM-DD-a-osx.tar.gz -C /
$ tar -xzf swift-LOCAL-YYYY-MM-DD-a-osx.tar.gz -C ~/
The script also generates an archive containing debug symbols which can be installed over the main archive allowing symbolication of any compiler crashes.
$ sudo tar -xzf swift-LOCAL-YYYY-MM-DD-a-osx-symbols.tar.gz -C /
$ tar -xzf swift-LOCAL-YYYY-MM-DD-a-osx-symbols.tar.gz -C ~/
Specify the local toolchain for Xcode's use via Xcode->Toolchains
.
Try the suggestions in Troubleshooting build issues.
Make sure you are using the correct release of Xcode.
If you have changed Xcode versions but still encounter errors that appear to be related to the Xcode version, try passing --clean
to build-script
.
When a new version of Xcode is released, you can update your build without recompiling the entire project by passing --reconfigure
to build-script
.
Be sure to look at the documentation index for a bird's eye view of the available documentation. In particular, the documents titled Debugging the Swift Compiler and Continuous Integration for Swift are very helpful to understand before submitting your first PR.
Author: Swiftwasm
Source Code: https://github.com/swiftwasm/swift
License: Apache-2.0 license
1667041740
SwiftUI-compatible framework for building browser apps with WebAssembly
At the moment Tokamak implements a very basic subset of SwiftUI. Its DOM renderer supports a few view types and modifiers (you can check the current list in the progress document), and a new HTML
view for constructing arbitrary HTML. The long-term goal of Tokamak is to implement as much of SwiftUI API as possible and to provide a few more helpful additions that simplify HTML and CSS interactions.
If there's some SwiftUI API that's missing but you'd like to use it, please review the existing issues and PRs to get more details about the current status, or create a new issue to let us prioritize the development based on the demand. We also try to make the development of views and modifiers easier (with the help from the HTML
view, see the example below), so pull requests are very welcome! Don't forget to check the "Contributing" section first.
If you'd like to participate in the growing SwiftWasm community, you're also very welcome to join our Discord server, or the #webassembly
channel in the SwiftPM Slack.
Tokamak API attempts to resemble SwiftUI API as much as possible. The main difference is that you use import TokamakShim
instead of import SwiftUI
in your files. The former makes your views compatible with Apple platforms, as well as platforms supported by Tokamak (currently only WebAssembly/WASI with more coming in the future):
import TokamakShim
struct Counter: View {
@State var count: Int
let limit: Int
var body: some View {
if count < limit {
VStack {
Button("Increment") { count += 1 }
Text("\(count)")
}
.onAppear { print("Counter.VStack onAppear") }
.onDisappear { print("Counter.VStack onDisappear") }
} else {
VStack { Text("Limit exceeded") }
}
}
}
@main
struct CounterApp: App {
var body: some Scene {
WindowGroup("Counter Demo") {
Counter(count: 5, limit: 15)
}
}
}
With the HTML
view you can also render any HTML you want, including inline SVG:
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",
])
}
}
}
HTML
doesn't support event listeners, and is declared in the TokamakStaticHTML
module, which TokamakDOM
re-exports. The benefit of HTML
is that you can use it for static rendering in libraries like TokamakVapor and TokamakPublish.
Another option is the DynamicHTML
view provided by the TokamakDOM
module, which has a listeners
property with a corresponding initializer parameter. You can pass closures that can handle onclick
, onmouseover
and other DOM events for you in the listeners
dictionary. Check out MDN docs for the full list.
An example of mouse events handling with DynamicHTML
would look like this:
struct MouseEventsView: View {
@State var position: CGPoint = .zero
@State var isMouseButtonDown: Bool = false
var body: some View {
DynamicHTML(
"div",
["style": "width: 200px; height: 200px; background-color: red;"],
listeners: [
"mousemove": { event in
guard
let x = event.offsetX.jsValue.number,
let y = event.offsetY.jsValue.number
else { return }
position = CGPoint(x: x, y: y)
},
"mousedown": { _ in isMouseButtonDown = true },
"mouseup": { _ in isMouseButtonDown = false },
]
) {
Text("position is \(position), is mouse button down? \(isMouseButtonDown)")
}
}
}
While JavaScriptKit
is a great option for occasional interactions with JavaScript, sometimes you need to inject arbitrary scripts or styles, which can be done through direct DOM access:
import JavaScriptKit
let document = JSObject.global.document
let script = document.createElement("script")
script.setAttribute("src", "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js")
document.head.appendChild(script)
_ = document.head.insertAdjacentHTML("beforeend", #"""
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
"""#)
This way both Semantic UI styles and moment.js localized date formatting (or any arbitrary style/script/font added that way) are available in your app.
A new reconciler modeled after React's Fiber reconciler is optionally available. It can provide faster updates and allow for larger View hierarchies. It also includes layout steps that can match SwiftUI layouts closer than CSS approximations.
You can specify which reconciler to use in your App
's configuration:
struct CounterApp: App {
static let _configuration: _AppConfiguration = .init(
// Specify `useDynamicLayout` to enable the layout steps in place of CSS approximations.
reconciler: .fiber(useDynamicLayout: true)
)
var body: some Scene {
WindowGroup("Counter Demo") {
Counter(count: 5, limit: 15)
}
}
}
Note: Not all
View
s andViewModifier
s are supported by Fiber renderers yet.
carton
0.15.x (carton is our build tool, see the "Getting started" section for installation steps)Any recent browser that supports WebAssembly and required JavaScript features should work, which currently includes:
If you need to support older browser versions, you'll have to build with JAVASCRIPTKIT_WITHOUT_WEAKREFS
flag, passing -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS
flags when compiling. This should lower browser requirements to these versions:
Not all of these versions are tested on regular basis though, compatibility reports are very welcome!
Tokamak relies on carton
as a primary build tool. As a part of these steps you'll install carton
via Homebrew on macOS (unfortunately you'll have to build it manually on Linux). Assuming you already have Homebrew installed, you can create a new Tokamak app by following these steps:
Install carton
:
brew install swiftwasm/tap/carton
If you had carton
installed before this, make sure you have version 0.15.0 or greater:
carton --version
Create a directory for your project and make it current:
mkdir TokamakApp && cd TokamakApp
Initialize the project from a template with carton
:
carton init --template tokamak
Build the project and start the development server, carton dev
can be kept running during development:
carton dev
Open http://127.0.0.1:8080/ in your browser to see the app running. You can edit the app source code in your favorite editor and save it, carton
will immediately rebuild the app and reload all browser tabs that have the app open.
You can also clone this repository and run carton dev --product TokamakDemo
in its root directory. This will build the demo app that shows almost all of the currently implemented APIs.
If you have any questions, pleaes check out the FAQ document, and/or join the #tokamak channel on the SwiftWasm Discord server.
By default, the DOM renderer will escape HTML control characters in Text
views. If you wish to override this functionality, you can use the _domTextSanitizer
modifier:
Text("<font color='red'>Unsanitized Text</font>")
._domTextSanitizer(Sanitizers.HTML.insecure)
You can also use custom sanitizers; the argument to _domTextSanitizer
is simply a String -> String
closure. If _domTextSanitizer
is applied to a non-Text
view, it will apply to all Text
in subviews, unless overridden.
If you use user-generated or otherwise unsafe strings elsewhere, make sure to properly sanitize them yourself.
unable to find utility "xctest"
error when buildingThis error can only happen on macOS, so make sure you have Xcode installed as listed in the requirements. If you do have Xcode installed but still get the error, please refer to this StackOverflow answer.
Open Package.swift
of your project that depends on Tokamak with Xcode and build it for macOS. As Xcode currently doesn't support cross-compilation for non-Apple platforms, your project can't be indexed if it doesn't build for macOS, even if it isn't fully function on macOS when running. If you need to exclude some WebAssembly-specific code in your own app that doesn't compile on macOS, you can rely on #if os(WASI)
compiler directives.
All relevant modules of Tokamak (including TokamakDOM
) should compile on macOS. You may see issues with TokamakShim
on macOS Catalina, where relevant SwiftUI APIs aren't supported, but replacing import TokamakShim
with import TokamakDOM
should resolve the issue until you're able to update to macOS Big Sur.
If you stumble upon code in Tokamak that doesn't build on macOS and prevents syntax highlighting or autocomplete from working in Xcode, please report it as a bug.
Make sure you have the SourceKit LSP extension installed. If you don't trust this unofficial release, please follow the manual building and installation guide. Apple currently doesn't provide an official build of the extension on the VSCode Marketplace unfortunately.
All contributions, no matter how small, are very welcome. You don't have to be a web developer or a SwiftUI expert to meaningfully contribute. In fact, by checking out how some of the simplest views are implemented in Tokamak you may learn more how SwiftUI may work under the hood.
Updating our documentation and taking on the starter bugs is also appreciated. Don't forget to join our Discord server to get in touch with the maintainers and other users. See CONTRIBUTING.md
for more details.
This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to conduct@tokamak.dev.
If this library saved you any amount of time or money, please consider sponsoring the work of its maintainers on their sponsorship pages: @carson-katri, @kateinoigakukun, and @MaxDesiatov. While some of the sponsorship tiers give you priority support or even consulting time, any amount is appreciated and helps in maintaining the project.
In alphabetical order: Carson Katri, Ezra Berch, Jed Fox, Morten Bek Ditlevsen, Yuta Saito.
SwiftUI is a trademark owned by Apple Inc. Software maintained as a part of the Tokamak project is not affiliated with Apple Inc.
Author: TokamakUI
Source Code: https://github.com/TokamakUI/Tokamak
License: Apache-2.0 license
1661996015
At the moment Tokamak implements a very basic subset of SwiftUI. Its DOM renderer supports a few view types and modifiers (you can check the current list in the progress document), and a new HTML
view for constructing arbitrary HTML. The long-term goal of Tokamak is to implement as much of SwiftUI API as possible and to provide a few more helpful additions that simplify HTML and CSS interactions.
If there's some SwiftUI API that's missing but you'd like to use it, please review the existing issues and PRs to get more details about the current status, or create a new issue to let us prioritize the development based on the demand. We also try to make the development of views and modifiers easier (with the help from the HTML
view, see the example below), so pull requests are very welcome! Don't forget to check the "Contributing" section first.
If you'd like to participate in the growing SwiftWasm community, you're also very welcome to join our Discord server, or the #webassembly
channel in the SwiftPM Slack.
Tokamak API attempts to resemble SwiftUI API as much as possible. The main difference is that you use import TokamakShim
instead of import SwiftUI
in your files. The former makes your views compatible with Apple platforms, as well as platforms supported by Tokamak (currently only WebAssembly/WASI with more coming in the future):
import TokamakShim
struct Counter: View {
@State var count: Int
let limit: Int
var body: some View {
if count < limit {
VStack {
Button("Increment") { count += 1 }
Text("\(count)")
}
.onAppear { print("Counter.VStack onAppear") }
.onDisappear { print("Counter.VStack onDisappear") }
} else {
VStack { Text("Limit exceeded") }
}
}
}
@main
struct CounterApp: App {
var body: some Scene {
WindowGroup("Counter Demo") {
Counter(count: 5, limit: 15)
}
}
}
With the HTML
view you can also render any HTML you want, including inline SVG:
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",
])
}
}
}
HTML
doesn't support event listeners, and is declared in the TokamakStaticHTML
module, which TokamakDOM
re-exports. The benefit of HTML
is that you can use it for static rendering in libraries like TokamakVapor and TokamakPublish.
Another option is the DynamicHTML
view provided by the TokamakDOM
module, which has a listeners
property with a corresponding initializer parameter. You can pass closures that can handle onclick
, onmouseover
and other DOM events for you in the listeners
dictionary. Check out MDN docs for the full list.
An example of mouse events handling with DynamicHTML
would look like this:
struct MouseEventsView: View {
@State var position: CGPoint = .zero
@State var isMouseButtonDown: Bool = false
var body: some View {
DynamicHTML(
"div",
["style": "width: 200px; height: 200px; background-color: red;"],
listeners: [
"mousemove": { event in
guard
let x = event.offsetX.jsValue.number,
let y = event.offsetY.jsValue.number
else { return }
position = CGPoint(x: x, y: y)
},
"mousedown": { _ in isMouseButtonDown = true },
"mouseup": { _ in isMouseButtonDown = false },
]
) {
Text("position is \(position), is mouse button down? \(isMouseButtonDown)")
}
}
}
While JavaScriptKit
is a great option for occasional interactions with JavaScript, sometimes you need to inject arbitrary scripts or styles, which can be done through direct DOM access:
import JavaScriptKit
let document = JSObject.global.document
let script = document.createElement("script")
script.setAttribute("src", "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js")
document.head.appendChild(script)
_ = document.head.insertAdjacentHTML("beforeend", #"""
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
"""#)
This way both Semantic UI styles and moment.js localized date formatting (or any arbitrary style/script/font added that way) are available in your app.
A new reconciler modeled after React's Fiber reconciler is optionally available. It can provide faster updates and allow for larger View hierarchies. It also includes layout steps that can match SwiftUI layouts closer than CSS approximations.
You can specify which reconciler to use in your App
's configuration:
struct CounterApp: App {
static let _configuration: _AppConfiguration = .init(
// Specify `useDynamicLayout` to enable the layout steps in place of CSS approximations.
reconciler: .fiber(useDynamicLayout: true)
)
var body: some Scene {
WindowGroup("Counter Demo") {
Counter(count: 5, limit: 15)
}
}
}
Note: Not all
View
s andViewModifier
s are supported by Fiber renderers yet.
carton
0.15.x (carton is our build tool, see the "Getting started" section for installation steps)Any recent browser that supports WebAssembly and required JavaScript features should work, which currently includes:
If you need to support older browser versions, you'll have to build with JAVASCRIPTKIT_WITHOUT_WEAKREFS
flag, passing -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS
flags when compiling. This should lower browser requirements to these versions:
Not all of these versions are tested on regular basis though, compatibility reports are very welcome!
Tokamak relies on carton
as a primary build tool. As a part of these steps you'll install carton
via Homebrew on macOS (unfortunately you'll have to build it manually on Linux). Assuming you already have Homebrew installed, you can create a new Tokamak app by following these steps:
carton
:brew install swiftwasm/tap/carton
If you had carton
installed before this, make sure you have version 0.15.0 or greater:
carton --version
mkdir TokamakApp && cd TokamakApp
carton
:carton init --template tokamak
carton dev
can be kept running during development:carton dev
carton
will immediately rebuild the app and reload all browser tabs that have the app open.You can also clone this repository and run carton dev --product TokamakDemo
in its root directory. This will build the demo app that shows almost all of the currently implemented APIs.
By default, the DOM renderer will escape HTML control characters in Text
views. If you wish to override this functionality, you can use the _domTextSanitizer
modifier:
Text("<font color='red'>Unsanitized Text</font>")
._domTextSanitizer(Sanitizers.HTML.insecure)
You can also use custom sanitizers; the argument to _domTextSanitizer
is simply a String -> String
closure. If _domTextSanitizer
is applied to a non-Text
view, it will apply to all Text
in subviews, unless overridden.
If you use user-generated or otherwise unsafe strings elsewhere, make sure to properly sanitize them yourself.
unable to find utility "xctest"
error when buildingThis error can only happen on macOS, so make sure you have Xcode installed as listed in the requirements. If you do have Xcode installed but still get the error, please refer to this StackOverflow answer.
Open Package.swift
of your project that depends on Tokamak with Xcode and build it for macOS. As Xcode currently doesn't support cross-compilation for non-Apple platforms, your project can't be indexed if it doesn't build for macOS, even if it isn't fully function on macOS when running. If you need to exclude some WebAssembly-specific code in your own app that doesn't compile on macOS, you can rely on #if os(WASI)
compiler directives.
All relevant modules of Tokamak (including TokamakDOM
) should compile on macOS. You may see issues with TokamakShim
on macOS Catalina, where relevant SwiftUI APIs aren't supported, but replacing import TokamakShim
with import TokamakDOM
should resolve the issue until you're able to update to macOS Big Sur.
If you stumble upon code in Tokamak that doesn't build on macOS and prevents syntax highlighting or autocomplete from working in Xcode, please report it as a bug.
Make sure you have the SourceKit LSP extension installed. If you don't trust this unofficial release, please follow the manual building and installation guide. Apple currently doesn't provide an official build of the extension on the VSCode Marketplace unfortunately.
All contributions, no matter how small, are very welcome. You don't have to be a web developer or a SwiftUI expert to meaningfully contribute. In fact, by checking out how some of the simplest views are implemented in Tokamak you may learn more how SwiftUI may work under the hood.
Updating our documentation and taking on the starter bugs is also appreciated. Don't forget to join our Discord server to get in touch with the maintainers and other users. See CONTRIBUTING.md
for more details.
This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to conduct@tokamak.dev.
If this library saved you any amount of time or money, please consider sponsoring the work of its maintainers on their sponsorship pages: @carson-katri, @kateinoigakukun, and @MaxDesiatov. While some of the sponsorship tiers give you priority support or even consulting time, any amount is appreciated and helps in maintaining the project.
In alphabetical order: Carson Katri, Ezra Berch, Jed Fox, Morten Bek Ditlevsen, Yuta Saito.
SwiftUI is a trademark owned by Apple Inc. Software maintained as a part of the Tokamak project is not affiliated with Apple Inc.
Tokamak is available under the Apache 2.0 license. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the LICENSE file for more info.
Author: TokamakUI
Source code: https://github.com/TokamakUI/Tokamak
License: Apache-2.0 license
#swift #webassembly
1640327478
At the moment Tokamak implements a very basic subset of SwiftUI. Its DOM renderer supports a few view types and modifiers (you can check the current list in the progress document), and a new HTML
view for constructing arbitrary HTML. The long-term goal of Tokamak is to implement as much of SwiftUI API as possible and to provide a few more helpful additions that simplify HTML and CSS interactions.
If there's some SwiftUI API that's missing but you'd like to use it, please review the existing issues and PRs to get more details about the current status, or create a new issue to let us prioritize the development based on the demand. We also try to make the development of views and modifiers easier (with the help from the HTML
view, see the example below), so pull requests are very welcome! Don't forget to check the "Contributing" section first.
If you'd like to participate in the growing SwiftWasm community, you're also very welcome to join our Discord server, or the #webassembly
channel in the SwiftPM Slack.
Tokamak API attempts to resemble SwiftUI API as much as possible. The main difference is that you use import TokamakShim
instead of import SwiftUI
in your files. The former makes your views compatible with Apple platforms, as well as platforms supported by Tokamak (currently only WebAssembly/WASI with more coming in the future):
import TokamakShim
struct Counter: View {
@State var count: Int
let limit: Int
var body: some View {
if count < limit {
VStack {
Button("Increment") { count += 1 }
Text("\(count)")
}
.onAppear { print("Counter.VStack onAppear") }
.onDisappear { print("Counter.VStack onDisappear") }
} else {
VStack { Text("Limit exceeded") }
}
}
}
@main
struct CounterApp: App {
var body: some Scene {
WindowGroup("Counter Demo") {
Counter(count: 5, limit: 15)
}
}
}
With the HTML
view you can also render any HTML you want, including inline SVG:
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",
])
}
}
}
HTML
doesn't support event listeners, and is declared in the TokamakStaticHTML
module, which TokamakDOM
re-exports. The benefit of HTML
is that you can use it for static rendering in libraries like TokamakVapor and TokamakPublish.
Another option is the DynamicHTML
view provided by the TokamakDOM
module, which has a listeners
property with a corresponding initializer parameter. You can pass closures that can handle onclick
, onmouseover
and other DOM events for you in the listeners
dictionary. Check out MDN docs for the full list.
An example of mouse events handling with DynamicHTML
would look like this:
struct MouseEventsView: View {
@State var position: CGPoint = .zero
@State var isMouseButtonDown: Bool = false
var body: some View {
DynamicHTML(
"div",
["style": "width: 200px; height: 200px; background-color: red;"],
listeners: [
"mousemove": { event in
guard
let x = event.offsetX.jsValue().number,
let y = event.offsetY.jsValue().number
else { return }
position = CGPoint(x: x, y: y)
},
"mousedown": { _ in isMouseButtonDown = true },
"mouseup": { _ in isMouseButtonDown = false },
]
) {
Text("position is \(position), is mouse button down? \(isMouseButtonDown)")
}
}
}
While JavaScriptKit
is a great option for occasional interactions with JavaScript, sometimes you need to inject arbitrary scripts or styles, which can be done through direct DOM access:
import JavaScriptKit
let document = JSObject.global.document
let script = document.createElement("script")
script.setAttribute("src", "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js")
document.head.appendChild(script)
_ = document.head.insertAdjacentHTML("beforeend", #"""
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
"""#)
This way both Semantic UI styles and moment.js localized date formatting (or any arbitrary style/script/font added that way) are available in your app.
Any recent browser that supports WebAssembly and required JavaScript features should work, which currently includes:
If you need to support older browser versions, you'll have to build with JAVASCRIPTKIT_WITHOUT_WEAKREFS
flag, passing -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS
flags when compiling. This should lower browser requirements to these versions:
Not all of these versions are tested on regular basis though, compatibility reports are very welcome!
Tokamak relies on carton
as a primary build tool. As a part of these steps you'll install carton
via Homebrew on macOS (unfortunately you'll have to build it manually on Linux). Assuming you already have Homebrew installed, you can create a new Tokamak app by following these steps:
carton
:brew install swiftwasm/tap/carton
If you had carton
installed before this, make sure you have version 0.12.0 or greater:
carton --version
mkdir TokamakApp && cd TokamakApp
carton
:carton init --template tokamak
carton dev
can be kept running during development:carton dev
carton
will immediately rebuild the app and reload all browser tabs that have the app open.You can also clone this repository and run carton dev --product TokamakDemo
in its root directory. This will build the demo app that shows almost all of the currently implemented APIs.
By default, the DOM renderer will escape HTML control characters in Text
views. If you wish to override this functionality, you can use the _domTextSanitizer
modifier:
Text("<font color='red'>Unsanitized Text</font>")
._domTextSanitizer(Sanitizers.HTML.insecure)
You can also use custom sanitizers; the argument to _domTextSanitizer
is simply a String -> String
closure. If _domTextSanitizer
is applied to a non-Text
view, it will apply to all Text
in subviews, unless overridden.
If you use user-generated or otherwise unsafe strings elsewhere, make sure to properly sanitize them yourself.
unable to find utility "xctest"
error when buildingThis error can only happen on macOS, so make sure you have Xcode installed as listed in the requirements. If you do have Xcode installed but still get the error, please refer to this StackOverflow answer.
Open Package.swift
of your project that depends on Tokamak with Xcode and build it for macOS. As Xcode currently doesn't support cross-compilation for non-Apple platforms, your project can't be indexed if it doesn't build for macOS, even if it isn't fully function on macOS when running. If you need to exclude some WebAssembly-specific code in your own app that doesn't compile on macOS, you can rely on #if os(WASI)
compiler directives.
All relevant modules of Tokamak (including TokamakDOM
) should compile on macOS. You may see issues with TokamakShim
on macOS Catalina, where relevant SwiftUI APIs aren't supported, but replacing import TokamakShim
with import TokamakDOM
should resolve the issue until you're able to update to macOS Big Sur.
If you stumble upon code in Tokamak that doesn't build on macOS and prevents syntax highlighting or autocomplete from working in Xcode, please report it as a bug.
Make sure you have the SourceKit LSP extension installed. If you don't trust this unofficial release, please follow the manual building and installation guide. Apple currently doesn't provide an official build of the extension on the VSCode Marketplace unfortunately.
See CONTRIBUTING.md
for more details.
This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to conduct@tokamak.dev.
If this library saved you any amount of time or money, please consider sponsoring the work of its maintainers on their sponsorship pages: @carson-katri, @kateinoigakukun, and @MaxDesiatov. While some of the sponsorship tiers give you priority support or even consulting time, any amount is appreciated and helps in maintaining the project.
In alphabetical order: Carson Katri, David Hunt, Ezra Berch, Jed Fox, Max Desiatov, Morten Bek Ditlevsen, Yuta Saito.
SwiftUI is a trademark owned by Apple Inc. Software maintained as a part of the Tokamak project is not affiliated with Apple Inc.
Download Details:
Author: TokamakUI
Source Code: https://github.com/TokamakUITokamak
License: Apache-2.0 License