Design
Core modules, render pipeline, and diff lifecycle
Design
Avocet is a small core engine for building and diffing HTML-like trees in Scala. The key idea is: a template is a function that writes rendering operations into a render context. Depending on the render context implementation, those operations become either:
an HTML string (static rendering), or
a compact byte-buffer encoded tree that can be diffed to infer changes (virtual-DOM-like).
Modules
avocet-core: DSL + optimizer + render contexts (includingDiffRenderContext)avocet-events: shared event/id model used by integrationsavocet-dom: Scala.js DOM backend that applies diffs to the browser DOM
The render pipeline
At runtime, an Avocet template is a Document[M] (usually created via the DSL as Node[M], Attr[M], Style[M]). Applying a document means calling methods on a RenderContext:
openNode(XmlNs, tag)setAttr(XmlNs, name, value)setStyle(name, value)addTextNode(text)closeNode(tag)addMisc(value)(integration side-channel)
DiffRenderContext lifecycle (and why finalizeDocument() matters)
DiffRenderContext keeps two internal buffers:
lhs: the most recently rendered document (current)
rhs: the previous document (baseline)
Diffing is a lifecycle. The important steps are:
Render by applying a
Documentto the render context (writes ops into lhs)Call
finalizeDocument()(flip lhs for reading + reset traversal state)Call
diff(performer)(read lhs/rhs and call the performer with inferred changes)Call
swap()to make the current buffer become the next baseline
Design note: DiffRenderContext is intentionally stateful. You typically keep one instance per render-loop (single-threaded) and reuse it across updates.
addMisc as an integration hook
addMisc(value) attaches an out-of-band payload to the current element id. Integrations (eg frameworks built on Avocet) use it to collect things like:
event handlers (keyed by element id + event type)
element ids for imperative access
component markers / other metadata