Runtime behavior
This page describes how Sercrod behaves in the browser after the script is loaded: how hosts are discovered, how data is read, how templates are rendered, and how directives are evaluated during updates.
Configuration details (for example cleanup or delimiters) are listed on the Config page. This page focuses on the runtime model.
This document is an implementation reference based on dist/sercrod.js.
If you use a different build, behavior may differ. When in doubt, prioritize observed runtime behavior.
1. Host discovery
A Sercrod host is a <serc-rod> element in the DOM.
When the script runs, it:
- registers the
serc-rodcustom element, - upgrades any existing
<serc-rod>in the current document, - and applies the same behavior to
<serc-rod>created later (for example via JavaScript).
Each host manages its own subtree. Sercrod does not take over the entire page. Normal HTML outside hosts is left as-is.
2. Data sources and scope
Each host renders against a scope object. At a high level:
host.datais the primary data for the host,- directives like
*letcan create a derived, local scope for a subtree, *globalcan update a wider data target so later evaluation sees the change.
If the host has a data="..." attribute, Sercrod may parse it as a small inline object. For example:
<serc-rod data='{"name":"Sercrod","count":0}'>...</serc-rod>
Sercrod also accepts data assigned from JavaScript:
host.data = { name: "Sercrod", count: 0 };
Nested hosts form independent rendering units. Data inheritance and composition patterns are described in the nested Sercrod guide.
3. Rendering model
Sercrod renders a host by rebuilding its DOM from the host template and the current scope. This is a regeneration model: the host subtree is constructed from template rules, not patched node-by-node.
Rendering is driven by two core ideas:
-
Structure directives first - directives like
*if,*switch,*each, and*fordecide what is rendered and what is skipped. - Fallback to generic element rendering - if no structure or early-exit directive applies, Sercrod renders the element normally (attributes, interpolation, children).
The exact evaluation order is documented in section 5.
4. Interpolation and directives
Inside a host, Sercrod supports two main ways to reflect data:
-
Interpolation - inline replacement of
%expr%in text and attribute values. -
Directives - attributes that control behavior, such as:
*let- define a local scope for a subtree,*print- print a value into an element,*if,*elseif,*else- conditional branches,*switch- switch-like branching,*each,*for- repeat rendering for collections,@event- call expressions on events, for example@click.
The directive list and per-directive rules are described in the Directives reference.
5. Updates and directive evaluation order
5.1 update() - full flow
An update re-renders the host. In dist/sercrod.js, update() follows this high-level flow:
- Execution guards - re-entry prevention and loop count guards are checked early. Some one-time behaviors (for example websocket reconnect on first or forced update) happen here.
-
Scope sync and render decision - staged data may be synchronized from a parent scope.
If
*lazyis enabled on a host, the host can skip its own render and update children only, then call*updated. -
Template rebuild - the host content is cleared and rebuilt from the template using the current scope.
If the host itself has
*for, it repeats with a changed scope per iteration. -
Post processing - plugin index rebuild,
*manoutput,*logscheduling (viarequestAnimationFrame), then*updated. After that, normal elements may absorb*updatedhooks. - Cleanup - finalize internal state, schedule any pending updates, and reset counters.
5.2 renderNode() - evaluation order
Each node is evaluated in a fixed order. Many directives are early-exit: if a directive matches, Sercrod renders that branch and returns immediately without running later steps.
-
Plain output - text nodes are expanded.
*literaloutputs its child HTML as a raw string. -
Scope pre-processing -
*letcan replace the local scope for this subtree.*globalcan updatehost.dataorglobalThisso later evaluation sees the change. -
Structure directives - evaluated in this order:
*if/*elseif/*else(chain)*switch*each*for
These directives decide structure. If a branch is chosen, it is rendered and renderNode() returns.
- Early decision for child Sercrod - if the node is a custom element host, the parent does not render its inner content. The instance is created or marked and then returns.
-
Non-structure directives (side effects, IO) - processed in this order, and return on hit:
*apply*restore*save*load*post*fetch*api
-
Fallback rendering - if no directive above matches, Sercrod performs generic element rendering:
attribute binding,
*print-style output, template include behavior, and recursive rendering of child nodes.
5.3 Why this order matters
- Structure directives run first so the final DOM shape is decided before side effects and IO.
- Many directives short-circuit evaluation. If a directive returns early, later directives on the same element are not processed.
-
Nested
<serc-rod>is treated as a separate unit. The parent does not render inside it.
6. Nested Sercrod hosts
Hosts can be nested:
<serc-rod data='{"name":"Sercrod"}'>
<p>Outer: %name%</p>
<serc-rod>
<p>Inner: %name%</p>
</serc-rod>
</serc-rod>
In nested setups:
- The outer host manages its own data and subtree.
- The inner host is a separate unit with its own lifecycle and update cycle.
- Data composition depends on how you configure and structure the nested host.
For recommended patterns, see Guide: nested Sercrod.
7. Cleanup and SSR notes
In normal browser usage, Sercrod keeps hosts alive as long as they are in the document. When a host is removed, event handlers and internal resources are released.
In SSG or SSR scenarios, pages are usually rendered once and written to disk. In those cases:
- cleanup options (for example removing Sercrod directives or handlers from the final HTML) are controlled by configuration, and
- the overall flow is described in SSG and SSR.