SwiftWebUI - A demo implementation of SwiftUI for the Web

Overview

SwiftWebUI

Swift5.1 macOS tuxOS Travis

More details can be found on the related blog post at the Always Right Institute.

At WWDC 2019 Apple announced SwiftUI. A single "cross platform", "declarative" framework used to build tvOS, macOS, watchOS and iOS UIs. SwiftWebUI is bringing that to the Web ✔️

Disclaimer: This is a toy project! Do not use for production. Use it to learn more about SwiftUI and its inner workings.

SwiftWebUI

So what exactly is SwiftWebUI? It allows you to write SwiftUI Views which display in a web browser:

import SwiftWebUI

struct MainPage: View {
  @State var counter = 0
  
  func countUp() { 
    counter += 1 
  }
  
  var body: some View {
    VStack {
      Text("🥑🍞 #\(counter)")
        .padding(.all)
        .background(.green, cornerRadius: 12)
        .foregroundColor(.white)
        .onTapGesture(self.countUp)
    }
  }
}

Results in:

Unlike some other efforts this doesn't just render SwiftUI Views as HTML. It also sets up a connection between the browser and the code hosted in the Swift server, allowing for interaction - buttons, pickers, steppers, lists, navigation, you get it all!

In other words: SwiftWebUI is an implementation of (many but not all parts of) the SwiftUI API for the browser.

To repeat the Disclaimer: This is a toy project! Do not use for production. Use it to learn more about SwiftUI and its inner workings.

Requirements

Update 2019-07-08: There are three options to run SwiftWebUI:

macOS Catalina

One can use a macOS Catalina installation to run SwiftWebUI. Make sure that the Catalina version matches your Xcode 11 beta! (“Swift ABI” 🤦‍♀️ )

Fortunately it is really easy to install Catalina on a separate APFS volume. And an installation of Xcode 11 is required to get the new Swift 5.1 features SwiftUI makes heavy use of. Got that? Very well!

Why is Catalina required? SwiftUI makes use of new Swift 5.1 runtime features (e.g. opaque result types). Those features are not available in the Swift 5 runtime that ships with Mojave. (another reason is the use of Combine which is only available in Catalina, though that part could be fixed using OpenCombine)

tuxOS

SwiftWebUI now runs on Linux using OpenCombine (also works without that, but then some things don't work, e.g. NavigationView).

A Swift 5.1 snapshot is required. We also provide a Docker image containing a 5.1 snapshot over here: helje5/swift.

Mojave

The Xcode 11beta iOS 13 simulators do run on Mojave. You might be able to run SwiftWebUI within an iOS app.

SwiftWebUI Hello World

To setup a SwiftWebUI project, create a "macOS tool project" in Xcode 11, then use the new SwiftPM integration and add https://github.com/SwiftWebUI/SwiftWebUI as a dependency.

Open the main.swift file and replace it's content with:

import SwiftWebUI

SwiftWebUI.serve(Text("Holy Cow!"))

Compile and run the app in Xcode, open Safari and hit http://localhost:1337/:

🥑 🍞 AvocadoToast

A small SwiftWebUI sample based on the SwiftUI Essentials "Avocado Toast App". Find it over here: AvocadoToast.

Who

Brought to you by The Always Right Institute and ZeeZide. We like feedback, GitHub stars, cool contract work, presumably any form of praise you can think of.

Comments
  • Linux port / NoCombine

    Linux port / NoCombine

    To run things on Linux we only really need a tiny subset of Combine, and the types for that are already prepared in Misc/NoCombine.swift.

    We just need a way to track the sinks attached to a PassthroughSubject.

    P.S.: A Swift 5.1 container would be also required of course.

    enhancement help wanted 
    opened by helje5 11
  • No available targets are compatible with triple

    No available targets are compatible with triple

    hello, so I want to try this library to see if I can make apps with it. but when I try the steps in https://github.com/carson-katri/swiftwebui-scripts, I get error when running the command (make), and I get the following error : cd testingAppweUI &&
    swift build --triple wasm32-unknown-wasi &&
    cp .build/debug/testingAppweUI ../dist/SwiftWASM.wasm &&
    wasm-strip ../dist/SwiftWASM.wasm &&
    gzip ../dist/SwiftWASM.wasm --best Fetching https://github.com/carson-katri/SwiftWebUI Fetching https://github.com/MaxDesiatov/Runtime Fetching https://github.com/kateinoigakukun/JavaScriptKit Cloning https://github.com/kateinoigakukun/JavaScriptKit Resolving https://github.com/kateinoigakukun/JavaScriptKit at 1edcf70 Cloning https://github.com/MaxDesiatov/Runtime Resolving https://github.com/MaxDesiatov/Runtime at wasi-build Cloning https://github.com/carson-katri/SwiftWebUI Resolving https://github.com/carson-katri/SwiftWebUI at develop error: unable to create target: 'No available targets are compatible with triple "wasm32-unknown-wasi"' error: unable to create target: 'No available targets are compatible with triple "wasm32-unknown-wasi"' 1 error generated. 1 error generated. [0/7] Compiling _CJavaScriptKit dummy.c make: *** [build] Error 1

    thank you for making this

    opened by AbdulwahabAlbahrani 4
  • [#47] Rewrite communication

    [#47] Rewrite communication

    Did rewrite connection to work with WebSocket. Theres few stuff which could be better. Isn't that always a case? Anyway. Need your input on this one.

    How to update DOM object from within timer or request? @helje5 I've implemented two way communication, however it sends empty changes array or it crashes on your asserts. Help needed :) Thanks!

    opened by shial4 3
  • Potential issues with `Binding` creation

    Potential issues with `Binding` creation

    Hi @helje5 I just re-watched this WWDC talk: https://developer.apple.com/videos/play/wwdc2019/226/

    At around 33:00 the speaker says that Binding does not capture references.

    I tested it with BindableObject's subscript to verify the behavior.

    public struct _Binding<Value> {
      private let _getter: () -> Value
      private let _setter: (Value) -> Void
      
      public var wrappedValue: Value {
        get {
          return _getter()
        }
        nonmutating set {
          _setter(newValue)
        }
      }
      
      public init(
        getValue getter: @escaping () -> Value,
        setValue setter: @escaping (Value) -> Void
      ) {
        _getter = getter
        _setter = setter
      }
    }
    
    class VM: BindableObject {
      let willChange = PassthroughSubject<Void, Never>()
      var value = ""
      
      public func getBinding<Subject>(
        keyPath path: ReferenceWritableKeyPath<VM, Subject>
      ) -> _Binding<Subject> {
        return _Binding(
          getValue: {
            self[keyPath: path]
          },
          setValue: { newValue in
            self[keyPath: path] = newValue
          }
        )
      }
    }
    
    var vm: VM = VM()
    print(CFGetRetainCount(vm)) // 2
    let biding_1: Binding<String> = vm[\.value]
    print(CFGetRetainCount(vm)) // 3 - captures the reference once.
    let biding_2 = vm.getBinding(keyPath: \.value)
    print(CFGetRetainCount(vm)) // 5 🐞 - captures the reference twice.
    

    You have similar code here:

    https://github.com/swiftwebui/SwiftWebUI/blob/develop/Sources/SwiftWebUI/Properties/BindableObject.swift#L28

    I suspect that they do use [unowned self] in one of the closures because the other closure is already known to capture the reference and it's not needed to do it twice. I think in case of the custom _Binding type from the example I would put it into the getter closure because it should be destroyed at first (I assume the top to bottom deallocation order here).

    question 
    opened by DevAndArtist 3
  •  Reference Swift WebUI

    Reference Swift WebUI

    I want to write a SwiftKitUI using the system's UIKit and AppKit support for the low version. But I don't know how to write it. I don't know if I can read it according to the source code of SwiftWebUI.

    question 
    opened by josercc 3
  • How to publish the binary product to a hosting service?

    How to publish the binary product to a hosting service?

    Hi,

    I am really impressed with the framework! I tested some syntaxes and they work flawlessly.

    However I am wondering if I can really use for publishing my personal website this way...

    How can I host the resulting SwiftWebUI binary to e.g. WordPress or AWS?

    I am asking this because I see that Wordpress requires HTML files (which I could not find inside the project) and AWS offers no MacOS instances (??)

    opened by ApostolisApo 2
  • Export to static web page

    Export to static web page

    Hi,

    I was thinking if we could achieve something like static web page result. As a product generated after build/run in the Xcode. What do you think?

    If you think it is possible I am more than happy to help :) Would need your help to direct me where to look, focus at.

    Cheers, Shial

    opened by shial4 2
  • `Spacer` not same as `SwiftUI`

    `Spacer` not same as `SwiftUI`

    HStack {
                    Text("\(index)")
                    Spacer()
                    Button(action: {
                        self.index += 1
                    }) {
                        Text("Cilie Me")
                    }
                }
    

    Text and Button not in Web Content Left And Right .Now in all Left Offset

    opened by josercc 2
  • Sample Example Run Xcode Beta3 Run Error?

    Sample Example Run Xcode Beta3 Run Error?

    dyld: Symbol not found: _$s7Combine11SubscribersO4SinkCy_xq_GAA11CancellableAAMc Referenced from: /Users/zhangxing/Library/Developer/Xcode/DerivedData/Tinker2-cxubagqiogijkfhczskwfdfwlmmb/Build/Products/Debug/Tinker2 Expected in: /System/Library/Frameworks/Combine.framework/Versions/A/Combine in /Users/zhangxing/Library/Developer/Xcode/DerivedData/Tinker2-cxubagqiogijkfhczskwfdfwlmmb/Build/Products/Debug/Tinker2

    opened by josercc 2
  • No

    No

    To repeat the disclaimer: This is a toy project! Do not use it for production. Use it to learn more about SwiftUI and its inner workings.

    image

    No, make it production-ready 😂😂😂😂

    No seriously, I need this in my life after a decade of HTML/CSS/JS 😭 I hope this project brings new perspective to the ecosystem.

    Cheers, and thank you for putting together this project.

    opened by yordis 1
  • Drop all `!important` in CSS

    Drop all `!important` in CSS

    What the title says. There are few !important in the CSS to hack-override SemanticUI styles. Those just need to be qualified more specific so they take preferences (e.g. by adding our own classes to the the style).

    help wanted 
    opened by helje5 0
  • Type '() -> Label' cannot conform to 'View'

    Type '() -> Label' cannot conform to 'View'

    I create subview Label (because is absent from here)

    struct Label: View {
    
        private let title: String
        private let systemImage: String
    
        init(_ title: String, systemImage: String) {
            self.title = title
            self.systemImage = systemImage
        }
    
        var body: some View {
            HStack {
                Text(title)
                Image(systemName: systemImage)
            }
        }
    }
    

    but have got error: Type '() -> Label' cannot conform to 'View' while try to put it in tabItem :(

    I use this syntax :)

             NewsListView().tabItem {
                   Label("Новости", systemImage: "newspaper") 
             }
    

    but when I change syntax to: NewsListView().tabItem(Label("....")) all working now.... hmm

    opened by iDevPro 0
  • Added support for View optionals, fixing @ViewBuilder conditionals.

    Added support for View optionals, fixing @ViewBuilder conditionals.

    Previously conditionals had to have a trailing "else {...}" at the end because of lack of optional support from the View protocol. This fix will introduce View optionals and make the behavior more like SwiftUI's View.

    Note: I had to add an optional check inside ComponentReflection.swift, I'm not 100% sure of the inner workings of this file but this doesn't seem to be causing any conflicts.

    opened by Samuel-IH 1
  • Style patching tree node (issue #42)

    Style patching tree node (issue #42)

    Hello, I have taken a recent interest in this project and have written a PR for issue #42 The idea of HTMLStylePatching node is to serve as a "container" to hold style patches, whenever we call the .patch function it will automatically hook into an existing patching node, or create a new one if it doesn't already exist.

    The sample code presented in #42 works properly now, however, I am still having minor issues chaining multiple shadows on the same view (CSS shadow blending issues).

    Lastly, I would like to note that my implementation in BackgroundModifier.swift isn't as clean as I wish (I had to copy the style switch from the HTML node). Perhaps there is a better way to do this.

    opened by Samuel-IH 0
  • The height of the root view should match the available browser height (was: Access to page color)

    The height of the root view should match the available browser height (was: Access to page color)

    Hi, I have the following code:

    struct MainPage: View {
        var body: some View {
            return VStack {
                OrderHistory(previousOrders: previousOrders)
            } .background(.black, cornerRadius: nil)
                .padding(0)
                .relativeWidth(1)
                .relativeHeight(1)
        }
    }
    

    Now the page looks like that: Снимок экрана 2020-05-16 в 15 35 03 How can I access the page color? I want the full black page.

    bug enhancement help wanted 
    opened by vBoykoGit 4
  • Change DynamicPropertyInfo.updateInView to use ptr instead of `inout`

    Change DynamicPropertyInfo.updateInView to use ptr instead of `inout`

    Even though the thing probably works fine, it gives a warning on Swift 5.2 for good reasons.

    This should grab the pointer to the actual view storage higher in the flow and pass it down.

    opened by helje5 0
  • EnvironmentObject EXC_BAD_ACCESS

    EnvironmentObject EXC_BAD_ACCESS

    EnvironmentObject value passed in view hierarchy changed on server callback crashes serwer.

    error: warning: couldn't get required object pointer (substituting NULL): Couldn't load 'self' because its value couldn't be evaluated

    error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0xfffffffffffffffd).

    Inside

    guard let box = slot.pointee.value as? StateValueBox else {
            fatalError(
              "@EnvironmentObject value is pointing to a different box type!")
          }
    

    To reproduce fetch changes from tag #52 https://github.com/shial4/SWUI-NextUp/tree/%2352

    1. build & run.
    2. Select sign in tab
    3. Enter credentials ([email protected], test123456)

    Click continue -> nothing will happen at first click (no clue why) wait like 5 seconds and click it second time. View will change and serwer will crash.

    opened by shial4 6
Releases(0.3.0)
  • 0.3.0(Jun 3, 2020)

    Relicensed under Apache license

    With this release, SwiftWebUI migrates away from the excellent but useless "Bad Code License" to the Apache license, see LICENSE.txt for details.

    Done to support the WASM fork of @carson-katri: https://github.com/carson-katri/SwiftWebUI

    Yay!

    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Oct 18, 2019)

    Just a few API updates for issue #43:

    • [x] BindableObject => ObservableObject
    • [x] ObjectBinding => ObservedObject
    • [x] tapAction => onTapGesture
    • [x] TabbedView => TabView
    Source code(tar.gz)
    Source code(zip)
  • 0.1.7(Jul 4, 2019)

  • 0.1.6(Jul 4, 2019)

  • 0.1.5(Jul 4, 2019)

    Builds with (and requires) Xcode 11b3.

    • the big propertyDelegate renaming
    • use UUIDs as session IDs as suggested in Issue #4
    • add a tinsy HelloWorld app (used to test whether things do run at all)
    Source code(tar.gz)
    Source code(zip)
Owner
SwiftWebUI
A toy implementation of SwiftUI for the Web
SwiftWebUI
COVID-19 SwiftUI Demo

COVID-19_SwiftUI_Demo About COVID-19_SwiftUI_Demo is the coronavirus information application using SwiftUI which is first introduced in WWDC19 keynote

Hưng Thái 17 Feb 9, 2022
A very simple Rick & Morty app to demo GraphQL + SwiftUI

MortyUI A very simple Rick & Morty app to demo GraphQL + SwiftUI Characters Character detail Episode This app have a very simple SwiftUI MVVM architec

Thomas Ricouard 445 Jan 3, 2023
A SwiftUI system components and interactions demo app

SwiftUI Kit A SwiftUI system components and interactions demo app based on iOS 14, macOS Big Sur, watchOS 7, and tvOS 14. Use the SwiftUI Kit app to s

Jordan Singer 2k Jan 6, 2023
A demo of how you can integrate SwiftUI and Airtable in your app

SwiftUI Airtable Demo This is a small, functional example app that demonstrates how you can use Airtable as a lightweight backend. I wouldn't recommen

Zack Shapiro 144 Oct 21, 2022
demo: REST API with SwiftUI

CatAPISwiftUI demo: REST API with SwiftUI The example API is the cat API. https://thecatapi.com/ You can watch me develope this code on my Youtube cha

Karin Prater 29 Dec 27, 2022
Demo implementing Modern MVVM with Combine and SwiftUI

ModernMVVM-Combine-SwiftUI Demo implementing Modern MVVM with Combine and SwiftUI Includes the following: Publishers feedback with needed extensions V

Ahmed M. Hassan 4 Dec 20, 2022
Demo to show Air Quality Indices of Cities (in India) using SwiftUI and Combine Framework

AirQualityMonitoring-SwiftUI-Combine Demo to show Air Quality Indices of Cities (in India) using SwiftUI and Combine Framework Demo Video City List wi

Minhaz Panara 0 Jan 23, 2022
The demo project to show how to organize code to make SwiftUI apps easy to be test.

TestableApp I combined the idea to use functional programming instead of an loader instance in ModelView(I prefer to think of it as a service) and Res

VictorK 2 Jan 7, 2022
A demo app to showcase testable, modern iOS development with SwiftUI and Combine on MVVM-C architecture.

Coinz_App_iOS A demo app to showcase testable, modern iOS development with SwiftUI and Combine on MVVM-C architecture. Tech Stack: Swift, SwiftUI, Com

Burhan Aras 0 Dec 26, 2021
A directory demo app written with SwiftUI, Core Data, and Alamofire

Directory-SwiftUI A directory demo app written with SwiftUI, Core Data, and Alamofire Getting Started Clone (or fork) this repo: git clone git@github.

Harold Martin 13 Dec 23, 2022
MatchedGeometryEffect - SwiftUI MatchedGeometry effect demo

SwiftUI MatchedGeometryEffect This is a demo project to experiment and learn the

Andras Samu 2 Oct 12, 2022
Stock is a MacOS menu bar app that helps you quickly save a web link, a file link, or a text by using drag and drop

Stock is a MacOS menu bar app that helps you quickly save a web link, a file link, or a text by using drag and drop

シュンジョーァ 19 Dec 4, 2022
An iOS app that visually clones Spotify's app and consumes the official Spotify's Web API to show(and play) songs, podcasts, artists and more.

SpotifyClone An iOS app that visually clones Spotify's app and consumes the official Spotify's Web API to show(and play) songs, podcasts, artists and

Gabriel Denoni 11 Dec 27, 2021
SwiftUI & Combine app using MovieDB API. With a custom Flux (Redux) implementation.

MovieSwiftUI MovieSwiftUI is an application that uses the MovieDB API and is built with SwiftUI. It demos some SwiftUI (& Combine) concepts. The goal

Thomas Ricouard 6.2k Jan 8, 2023
SwiftUI implementation of Conway’s Game of Life — also known as “Life”.

Life Conway’s Game of Life SwiftUI implementation of Conway’s Game of Life — also known simply as “Life”. About I’m Martin, an indie dev from Berlin.

Martin Lexow 23 Jan 21, 2022
SwiftUI implementation of xcodes by RobotsAndPencils

XcodeUpdates SwiftUI implementation of xcodes by RobotsAndPencils Screenshots Technical Details Project supports macOS Big Sur (11.+) Project is writt

Ruslan Alikhamov 222 Oct 2, 2022
A SwiftUI implementation of React Hooks. Enhances reusability of stateful logic and gives state and lifecycle to function view.

SwiftUI Hooks A SwiftUI implementation of React Hooks. Enhances reusability of stateful logic and gives state and lifecycle to function view. Introduc

Ryo Aoyama 441 Jan 6, 2023
Demo app for Podlodka Crew 5

PodlodkaFiles Demo app for Podlodka Crew 5 shows two approaches for the persistence layer architecture: Normalized in-memory storage based on Swift va

Pavel Osipov 11 Nov 22, 2022