VTree icon indicating copy to clipboard operation
VTree copied to clipboard

VirtualDOM for Swift (iOS, macOS)

VTree

VirtualDOM for Swift (iOS, macOS), inspired by Matt-Esch/virtual-dom and elm-lang/virtual-dom.

See inamiy/SwiftElm for practical use.

Pseudocode

// ===== VTree.framework =====

protocol VTree {
    ...
    var children: [VTree] { get }
}

struct VView: VTree { ... }   // Virtual UIView
struct VLabel: VTree { ... }  // Virtual UILabel
...

// ========= Example =========

typealias State = Int  // can be any type

// Generate immutable `VTree` from `State`.
func render(state: State) -> VTree {
    return VView(children: [
        VLabel(text: "\(state)")
    ])
}

// Initialize `State`, `VTree`, and `UIView`.
var state = 0
var tree = render(state)
var view = createView(tree)

// Update logic: Timer updates `state` and re-render.
timer(1) {
    state += 1
    let newTree = render(state)
    let patch = diff(old: tree, new: newTree)
    view = apply(patch: patch, to: view)
}

This is an example of timer updating a count in view.label.

Unlike setting view.label.text = "\(state)" or any data bindings e.g. reactive programming that directly mutates variables from all over the place, VTree minimizes such side-effects by:

  1. Generating an immutable VTree from a single state
  2. Calculating a patch using an efficient diff algorithm, and
  3. Mutating a view only by calling apply

This seems like too much calculation for just tweaking a single variable, but it eventually prevents us from making stupid side-effects that is the 99% cause of our app's bugs.

Above code is just a pseudocode for simple protocol VTree. For better type-safety, protocol VTree will require associatedtype and also type-erasure techinique.

Please see Tests/DiffSpec.swift for more examples.

Metaprogramming with Sourcery

VTree uses Sourcery as Swift template metaprogramming engine to cover transcripting that elm-lang/core does when converting enum MyMsg to JavaScript.

By using Scripts/generate-message.sh, VTree will support AutoMessage to auto-generate extension MyMsg: Message. This is a requisite for VTree when interacting Cocoa events with user's enum Msg.

# Usage: ./generate-message.sh <source_dir> <code-generated-dir>
$ ./path/to/VTree/Scripts/generate-message.sh ./Demo/Sources ./Demo/Sources/CodeGenerated/

So that user can simplify enum MyMsg as:

enum MyMsg: AutoMessage {
    // NOTE: `MessageContext` is always required when enum-case (value constructor) requires arguments.
    case tap(GestureContext)
    case pan(PanGestureContext)
}

Feature

  • [x] ~~Handle more complicated cocoa events e.g. mouse, gesture, keyboard.~~ MessageContext
  • [x] ~~Add better layouting system, e.g. CSS Flexbox.~~ inamiy/Flexbox
  • [ ] Create more VTree concrete types for virtual UI***View.

License

MIT