Skip to content

Commit

Permalink
Update for JSKit 0.11.1, add async task modifier (#457)
Browse files Browse the repository at this point in the history
I've also moved sources in `TokamakDemo` directory into their respective subdirectories for easier navigation.

* Update for JSKit 0.11.0, add async `task` modifier

* Add back new file locations to `NativeDemo`

* Add compiler `#if` check to `TaskDemo`

* Update to JavaScriptKit 0.11.1

* Restrict `TaskDemo` with `compiler(>=5.5)` check

* Replace `compiler` with `swift` in some places

* Revert "Replace `compiler` with `swift` in some places"

This reverts commit 534784c.

* Use Xcode 13.2 on GitHub Actions hosts

* Find `TokamakPackageTests` in the build directory

* Fix macOS tests bundle path

* Make `task` modifier available only on macOS Monterey

* Revert "Use Xcode 13.2 on GitHub Actions hosts"

This reverts commit 63d044f.

* Revert "Fix macOS tests bundle path"

This reverts commit 3ccbc98.

* Revert "Find `TokamakPackageTests` in the build directory"

This reverts commit 68c845b.

* Use `canImport(Concurrency)` as an ultimate check

* Use `compiler(>=5.5) && canImport(Concurrency)`

* Clarify new browser version requirements in `README.md`

* Account for `_Concurrency` naming

* Update `README.md`

* Update README.md

Co-authored-by: ezraberch <49635435+ezraberch@users.noreply.github.com>
  • Loading branch information
MaxDesiatov and ezraberch authored Nov 23, 2021
1 parent a5a05b4 commit cbfdc34
Show file tree
Hide file tree
Showing 46 changed files with 442 additions and 225 deletions.
418 changes: 244 additions & 174 deletions NativeDemo/TokamakDemo.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/swiftwasm/JavaScriptKit.git",
"state": {
"branch": null,
"revision": "b19e7c8b10a2750ed47753e31ed13613171f3294",
"version": "0.10.1"
"revision": "309e63c03d8116210ad0437f5d1f09a26d4de48b",
"version": "0.11.1"
}
},
{
Expand All @@ -24,8 +24,8 @@
"repositoryURL": "https://github.com/swiftwasm/OpenCombineJS.git",
"state": {
"branch": null,
"revision": "eaf324ce78710f53b52fb82e9a8de4693633e33a",
"version": "0.1.1"
"revision": "f1f1799ddbb9876a0ef8c5700a3b78d352d0b969",
"version": "0.1.2"
}
},
{
Expand Down
44 changes: 28 additions & 16 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@

import PackageDescription

var tokamakDOMDependencies: [Target.Dependency] = [
"TokamakCore",
"TokamakStaticHTML",
.product(
name: "OpenCombineShim",
package: "OpenCombine"
),
.product(
name: "JavaScriptKit",
package: "JavaScriptKit",
condition: .when(platforms: [.wasi])
),
"OpenCombineJS",
]

#if compiler(>=5.5) && (canImport(Concurrency) || canImport(_Concurrency))
tokamakDOMDependencies.append(
.product(
name: "JavaScriptEventLoop",
package: "JavaScriptKit",
condition: .when(platforms: [.wasi])
)
)
#endif

let package = Package(
name: "Tokamak",
platforms: [
Expand Down Expand Up @@ -51,15 +76,15 @@ let package = Package(
// .package(url: /* package url */, from: "1.0.0"),
.package(
url: "https://github.com/swiftwasm/JavaScriptKit.git",
.upToNextMinor(from: "0.10.0")
.upToNextMinor(from: "0.11.1")
),
.package(
url: "https://github.com/OpenCombine/OpenCombine.git",
from: "0.12.0"
),
.package(
url: "https://github.com/swiftwasm/OpenCombineJS.git",
.upToNextMinor(from: "0.1.1")
.upToNextMinor(from: "0.1.2")
),
.package(
name: "Benchmark",
Expand Down Expand Up @@ -152,20 +177,7 @@ let package = Package(
),
.target(
name: "TokamakDOM",
dependencies: [
"TokamakCore",
"TokamakStaticHTML",
.product(
name: "OpenCombineShim",
package: "OpenCombine"
),
.product(
name: "JavaScriptKit",
package: "JavaScriptKit",
condition: .when(platforms: [.wasi])
),
"OpenCombineJS",
]
dependencies: tokamakDOMDependencies
),
.executableTarget(
name: "TokamakDemo",
Expand Down
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,33 @@ app.

## Requirements for app developers

- macOS 11 and Xcode 13.0. *Xcode 13.1 is currently not supported.*
- macOS 11 and Xcode 13.0 or later. Xcode 13.2 or later is recommended if you're developing
multi-platform apps that target WebAssembly and macOS at the same time, as these versions support
Swift concurrency back-deployment.
- [Swift 5.4 or later](https://swift.org/download/) and Ubuntu 18.04 if you'd like to use Linux.
Other Linux distributions are currently not supported.

## Requirements for app users

Any browser that [supports WebAssembly](https://caniuse.com/#feat=wasm) should work, which currently includes:
Any recent browser that [supports WebAssembly](https://caniuse.com/#feat=wasm) and [required
JavaScript features](https://caniuse.com/?search=finalizationregistry) should work, which currently includes:

- Edge 84+
- Firefox 79+
- Chrome 84+
- Desktop Safari 14.1+
- Mobile Safari 14.8+

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:

- Edge 16+
- Firefox 61+
- Chrome 66+
- (Mobile) Safari 12+

Not all of these were tested though, compatibility reports are very welcome!
Not all of these versions are tested on regular basis though, compatibility reports are very welcome!

## Getting started

Expand All @@ -141,7 +154,7 @@ app by following these steps:
brew install swiftwasm/tap/carton
```

If you had `carton` installed before this, make sure you have version 0.11.0 or greater:
If you had `carton` installed before this, make sure you have version 0.12.0 or greater:

```
carton --version
Expand Down
32 changes: 32 additions & 0 deletions Sources/TokamakCore/Modifiers/TaskModifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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 for the specific language governing permissions and
// limitations under the License.

#if compiler(>=5.5) && (canImport(Concurrency) || canImport(_Concurrency))

public extension View {
func task(
priority: TaskPriority = .userInitiated,
_ action: @escaping @Sendable () async -> ()
) -> some View {
var task: Task<(), Never>?
return onAppear {
task = Task(priority: priority, operation: action)
}
.onDisappear {
task?.cancel()
}
}
}

#endif
2 changes: 1 addition & 1 deletion Sources/TokamakCore/Shapes/Path/PathLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public extension Path {

func applying(_ transform: CGAffineTransform) -> Path {
guard transform != .identity else { return self }
let elements = self.elements.map { transform.transform(element: $0) }
let elements = elements.map { transform.transform(element: $0) }
let box = _PathBox(elements: elements)
return Path(storage: .path(box), sizing: .fixed)
}
Expand Down
4 changes: 3 additions & 1 deletion Sources/TokamakDOM/DOMNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ extension AnyHTML {
additionalAttributes: [HTMLAttribute: String],
transaction: Transaction
) {
let attributes = self.attributes.merging(additionalAttributes, uniquingKeysWith: +)
let attributes = attributes.merging(additionalAttributes, uniquingKeysWith: +)

dom.applyAttributes(attributes, with: transaction)

Expand Down Expand Up @@ -109,7 +109,9 @@ final class DOMNode: Target {
func reinstall(_ listeners: [String: Listener]) {
for (event, jsClosure) in self.listeners {
_ = ref.removeEventListener!(event, jsClosure)
#if JAVASCRIPTKIT_WITHOUT_WEAKREFS
jsClosure.release()
#endif
}
self.listeners = [:]

Expand Down
8 changes: 8 additions & 0 deletions Sources/TokamakDOM/DOMRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import OpenCombineJS
@_spi(TokamakCore) import TokamakCore
import TokamakStaticHTML

#if compiler(>=5.5) && (canImport(Concurrency) || canImport(_Concurrency))
import JavaScriptEventLoop
#endif

public typealias Sanitizers = TokamakStaticHTML.Sanitizers

extension EnvironmentValues {
Expand Down Expand Up @@ -87,6 +91,10 @@ final class DOMRenderer: Renderer {
rootRef = ref
appendRootStyle(ref)

#if compiler(>=5.5) && (canImport(Concurrency) || canImport(_Concurrency))
JavaScriptEventLoop.installGlobalExecutor()
#endif

let scheduler = JSScheduler()
self.scheduler = scheduler
reconciler = StackReconciler(
Expand Down
16 changes: 8 additions & 8 deletions Sources/TokamakDOM/Views/Canvas/Canvas.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ struct _Canvas<Symbols: View>: View {
HTML("canvas", [
"style": "width: 100%; height: 100%;",
])
._domRef($coordinator.canvas)
.onAppear { draw(in: proxy.size) }
._onUpdate {
// Cancel the previous animation loop.
if let currentDrawLoop = coordinator.currentDrawLoop {
_ = JSObject.global.cancelAnimationFrame!(currentDrawLoop)
}
draw(in: proxy.size)
._domRef($coordinator.canvas)
.onAppear { draw(in: proxy.size) }
._onUpdate {
// Cancel the previous animation loop.
if let currentDrawLoop = coordinator.currentDrawLoop {
_ = JSObject.global.cancelAnimationFrame!(currentDrawLoop)
}
draw(in: proxy.size)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ public struct ButtonStyleDemo: View {
Text("Label").padding(.leading, 5)
}
})
.buttonStyle(
PressedButtonStyle(pressedColor: Color.red)
)
.buttonStyle(
PressedButtonStyle(pressedColor: Color.red)
)
if #available(iOS 15.0, macOS 12.0, *) {
Button("Prominent") {}
.buttonStyle(BorderedProminentButtonStyle())
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ private final class HashState: ObservableObject {

deinit {
window.onhashchange = .undefined
#if JAVASCRIPTKIT_WITHOUT_WEAKREFS
onHashChange.release()
#endif
}
}

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
22 changes: 22 additions & 0 deletions Sources/TokamakDemo/Modifiers/ShadowDemo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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 for the specific language governing permissions and
// limitations under the License.

import TokamakShim

struct ShadowDemo: View {
var body: some View {
Color.red.frame(width: 60, height: 60, alignment: .center)
.shadow(color: .black, radius: 5, x: 0, y: 10)
}
}
61 changes: 61 additions & 0 deletions Sources/TokamakDemo/Modifiers/TaskDemo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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 for the specific language governing permissions and
// limitations under the License.

#if os(WASI) && compiler(>=5.5) && (canImport(Concurrency) || canImport(_Concurrency))
import JavaScriptKit
import TokamakDOM

private let jsFetch = JSObject.global.fetch.function!
private func fetch(_ url: String) -> JSPromise {
JSPromise(jsFetch(url).object!)!
}

private struct Response: Decodable {
let uuid: String
}

struct TaskDemo: View {
@State private var response: Result<Response, Error>?

var body: some View {
VStack {
switch response {
case let .success(response):
Text("Fetched UUID is \(response.uuid)")
case let .failure(error):
Text("Error is \(error)")
default:
Text("Response not available yet")
}

Button("Fetch new UUID asynchronously") {
response = nil
Task { await fetchResponse() }
}
}.task {
await fetchResponse()
}
}

func fetchResponse() async {
do {
let fetchResult = try await fetch("https://httpbin.org/uuid").value
let json = try await JSPromise(fetchResult.json().object!)!.value
response = Result { try JSValueDecoder().decode(Response.self, from: json) }
} catch {
response = .failure(error)
}
}
}
#endif
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
8 changes: 0 additions & 8 deletions Sources/TokamakDemo/ShadowDemo.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ struct TextDemo: View {
.heavy,
.black,
], id: \.self) { weight in
Text("a")
.fontWeight(weight)
Text("a")
.fontWeight(weight)
}
}
VStack {
Expand Down
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions Sources/TokamakDemo/TokamakDemo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ struct TokamakDemoView: View {
}
Section(header: Text("Modifiers")) {
NavItem("Shadow", destination: ShadowDemo())
#if os(WASI) && compiler(>=5.5) && (canImport(Concurrency) || canImport(_Concurrency))
NavItem("Task", destination: TaskDemo())
#endif
}
Section(header: Text("Selectors")) {
NavItem("DatePicker", destination: DatePickerDemo())
Expand Down
Loading

0 comments on commit cbfdc34

Please sign in to comment.