Pickleboyonline / solid-native

React Native but for Solid.JS
https://pickleboyonline.github.io/solid-native/
MIT License
15 stars 2 forks source link

Basic iOS Support #1

Closed Pickleboyonline closed 1 year ago

Pickleboyonline commented 1 year ago

So far, I've gotten a basic framework in about ~300 lines of code. The idea here is to utilize SwiftUI's rendering engine to manage most of the complex code/layout. Solid Native simply puts a light VDOM that is accessible to the SolidJS renderer. The VDOM is essentially a tree data structure composed of SolidNativeElements.

As for the JSI, I mainly use JavascriptCore's JSExport to export the native Swift objects to the JS environment. The reason for using JSC instead of React native Hermes is that it's easier to use and expose classes. Hermes doesn't exactly provide descriptive documentation, so I would find integrating difficult. The only downside is that startup times would be slower in exchange for a smaller binary and easier developer experience.

From a developer's POV when making modules, it functions similarly to React. Props are drilled down through a Prop ObserableObject. These props come from SolidJS. To emulate a Ref that is called through the onRef prop, use the Ref ObserableObject. The API could use some work to make it easier to extend, however.

Now, I need to do the following:

Pickleboyonline commented 1 year ago

Instead of hermes, it may be interesting to transpile JS => Kotlin Multiplatform

Pickleboyonline commented 1 year ago

I was able to implement a basic counter example with a SwiftUI wrapper that manages props/children/state. So far I am manipulating the UI with Swift code, now I need to expose the SolidNativeCore over the JSI to have SolidJS call these methods.

A snippet of the setup:

import SwiftUI
import JavaScriptCore

let sharedSolidNativeCore = SolidNativeCore()

@main
struct solid_native_ios_playgroundApp: App {
    var rootElement: AnySolidNativeElement
    let jsContext = JSContext()!

    init() {
        sharedSolidNativeCore.registerElements()
        let root = sharedSolidNativeCore.createRootElement(name: "v_stack")
        let button =  sharedSolidNativeCore.createRootElement(name: "button")
        let text = sharedSolidNativeCore.createRootElement(name: "sn_text")
        rootElement = root

        var inc = 0

        root.insertBefore(element: button, anchor: nil)

        root.insertBefore(element: text, anchor: button)

        text.setProp("text", "Count: 0")

        button.setProp("title", "Increment!")

        button.setProp("onPress", {
            inc += 1
            text.setProp("text", "Count \(inc)")
        })
    }

    var body: some Scene {
        WindowGroup {
            Group {
                rootElement.render()
            }
        }
    }
}

I plan on using vite with deno to transpile the TS code into JS code and subsequently open that to iOS. I believe the JavascriptCode module has a function to download JS source code from a URL, so I would probably just need to point it to the vite instance.

Pickleboyonline commented 1 year ago

Subtask: #2

Pickleboyonline commented 1 year ago

I now have basic ios support. I will close this issue for smaller more specific issues. See counter example:

https://github.com/Pickleboyonline/solid-native/assets/16438041/2bb1975b-24bf-4863-89cb-563aa2961116