Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for JSKit 0.11.1, add async task modifier #457

Merged
merged 20 commits into from
Nov 23, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
67ca99b
Update for JSKit 0.11.0, add async `task` modifier
MaxDesiatov Nov 22, 2021
d0bff4b
Add back new file locations to `NativeDemo`
MaxDesiatov Nov 22, 2021
8932bd0
Add compiler `#if` check to `TaskDemo`
MaxDesiatov Nov 22, 2021
b65300f
Update to JavaScriptKit 0.11.1
MaxDesiatov Nov 22, 2021
2ee9fc5
Restrict `TaskDemo` with `compiler(>=5.5)` check
MaxDesiatov Nov 22, 2021
534784c
Replace `compiler` with `swift` in some places
MaxDesiatov Nov 22, 2021
7382291
Revert "Replace `compiler` with `swift` in some places"
MaxDesiatov Nov 22, 2021
63d044f
Use Xcode 13.2 on GitHub Actions hosts
MaxDesiatov Nov 22, 2021
68c845b
Find `TokamakPackageTests` in the build directory
MaxDesiatov Nov 22, 2021
3ccbc98
Fix macOS tests bundle path
MaxDesiatov Nov 22, 2021
bac82ce
Make `task` modifier available only on macOS Monterey
MaxDesiatov Nov 22, 2021
4d25ff4
Revert "Use Xcode 13.2 on GitHub Actions hosts"
MaxDesiatov Nov 22, 2021
2fa2e3e
Revert "Fix macOS tests bundle path"
MaxDesiatov Nov 22, 2021
55001d2
Revert "Find `TokamakPackageTests` in the build directory"
MaxDesiatov Nov 22, 2021
05728f5
Use `canImport(Concurrency)` as an ultimate check
MaxDesiatov Nov 22, 2021
226fce6
Use `compiler(>=5.5) && canImport(Concurrency)`
MaxDesiatov Nov 22, 2021
a9bbf19
Clarify new browser version requirements in `README.md`
MaxDesiatov Nov 22, 2021
d23a296
Account for `_Concurrency` naming
MaxDesiatov Nov 23, 2021
14ace42
Update `README.md`
MaxDesiatov Nov 23, 2021
cf0ad83
Update README.md
MaxDesiatov Nov 23, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 are recommended if you're developing
MaxDesiatov marked this conversation as resolved.
Show resolved Hide resolved
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
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
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 {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved from existing ShadowDemo.swift, but for some reason git didn't pick it up.

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
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
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