View Source Updates

Whenever the template changes, a diff event is sent to the client. liveview-native-core handles most of this process.

Update Process

  1. When the page loads, Phoenix sends a JSON representation of the Phoenix.LiveView.Rendered struct
  2. The client parses this data, and forms a complete HTML document. It passes this HTML string to core to be parsed.
  3. Core sends back a Document with parsed nodes and elements, which the client renders to native elements
  4. The client sends an event in response to some user interaction
  5. The LiveView computes the changes, and sends a fragment diff to the client.
  6. The client merges this fragment diff with the previous Rendered struct, and sends the complete HTML to core to parse.
  7. Core returns a parsed document.
  8. The client asks core to merge the new document into the old document so they match.
  9. Core sends the ID of any changed nodes to the client to update.
LiveViewClientCore1. Rendered JSON2. Parse HTML3. Document4. Event "increment"5. Rendered Diff6. Parse New HTML7. New Document8. Merge Documents9. Changed NodeRefsLiveViewClientCore

Update Isolation

To keep updates fast, individual Views are updated based on the elements that change between a diff.

The LiveViewCoordinator stores a dictionary that maps a NodeRef to a Combine publisher.

Whenever core sends an update event for this NodeRef, a signal is sent through the corresponding publisher to all of its subscribers.

@ObservedElement

The ObservedElement property wrapper watches for changes to the node, and triggers a View update when change events are received.

This is done through the Observer class. It subscribes to the Combine publisher for the matching NodeRef.

One Observer instance is created for each View to avoid redundant subscriptions in the case of multiple ObservedElement wrappers (common when using @Attribute).

Node #1 SwiftUI View
Environment
LiveViewCoordinator
node #1 changed
node #1 changed
@ObservedElement
@Attribute
@Attribute
@ObservedElement
@ObservedElement
Observer
LiveViewCoordinator
Node #1 Publisher
Node #2 Publisher
Node #... Publisher