Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "none",
"comment": "Add documentation on FAST templating",
"packageName": "@microsoft/fast-element",
"email": "7559015+janechu@users.noreply.github.com",
"dependentChangeType": "none"
}
6 changes: 3 additions & 3 deletions packages/fast-element/docs/api-report.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,15 +509,15 @@ export const html: HTMLTemplateTag;
export class HTMLBindingDirective implements HTMLDirective, ViewBehaviorFactory, ViewBehavior, Aspected, BindingDirective {
constructor(dataBinding: Binding);
aspectType: DOMAspect;
// @internal (undocumented)
// @internal
bind(controller: ViewController): void;
createBehavior(): ViewBehavior;
createHTML(add: AddViewBehaviorFactory): string;
// (undocumented)
dataBinding: Binding;
// @internal (undocumented)
// @internal
handleChange(binding: Expression, observer: ExpressionObserver): void;
// @internal (undocumented)
// @internal
handleEvent(event: Event): void;
id: string;
policy: DOMPolicy;
Expand Down
17 changes: 17 additions & 0 deletions packages/fast-element/src/components/hydration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ import type {
import type { HydrationView } from "../templating/view.js";
import { FAST } from "../platform.js";

/**
* Regex patterns for parsing hydration markers embedded as HTML comments by the SSR renderer.
* Each marker type encodes factory indices so the client can map markers back to ViewBehaviorFactories.
*
* Content binding markers bracket text/template content:
* <!-- fe-b$$start$$<factoryIndex>$$<uniqueId>$$fe-b -->
* ...content...
* <!-- fe-b$$end$$<factoryIndex>$$<uniqueId>$$fe-b -->
*
* Repeat markers bracket each repeated item:
* <!-- fe-repeat$$start$$<itemIndex>$$fe-repeat -->
* <!-- fe-repeat$$end$$<itemIndex>$$fe-repeat -->
*
* Element boundary markers demarcate nested custom elements so parent walkers can skip them:
* <!-- fe-eb$$start$$<elementId>$$fe-eb -->
* <!-- fe-eb$$end$$<elementId>$$fe-eb -->
*/
const bindingStartMarker = /fe-b\$\$start\$\$(\d+)\$\$(.+)\$\$fe-b/;
const bindingEndMarker = /fe-b\$\$end\$\$(\d+)\$\$(.+)\$\$fe-b/;
const repeatViewStartMarker = /fe-repeat\$\$start\$\$(\d+)\$\$fe-repeat/;
Expand Down
23 changes: 22 additions & 1 deletion packages/fast-element/src/hydration/target-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,23 @@ function isShadowRoot(node: Node): node is ShadowRoot {
}

/**
* Maps {@link CompiledViewBehaviorFactory} ids to the corresponding node targets for the view.
* Maps compiled ViewBehaviorFactory IDs to their corresponding DOM nodes in the
* server-rendered shadow root. Uses a TreeWalker to scan the existing DOM between
* firstNode and lastNode, parsing hydration markers to build the targets map.
*
* For element nodes: parses `data-fe-b` (or variant) attributes to identify which
* factories target each element, then removes the marker attribute.
*
* For comment nodes: parses content binding markers (`fe-b$$start/end$$`) to find
* the DOM range controlled by each content binding. Single text nodes become the
* direct target; multi-node ranges are stored in boundaries for structural directives.
* Element boundary markers (`fe-eb$$start/end$$`) cause the walker to skip over
* nested custom elements that handle their own hydration.
*
* Host bindings (targetNodeId='h') appear at the start of the factories array but
* have no SSR markers β€” getHydrationIndexOffset() computes how many to skip so that
* marker indices align with the correct non-host factories.
*
* @param firstNode - The first node of the view.
* @param lastNode - The last node of the view.
* @param factories - The Compiled View Behavior Factories that belong to the view.
Expand Down Expand Up @@ -270,6 +286,11 @@ function skipToElementBoundaryEndMarker(node: Comment, walker: TreeWalker) {
}
}

/**
* Counts how many factories at the start of the array are host bindings (targetNodeId='h').
* Host bindings target the custom element itself and are not represented by SSR markers,
* so the marker indices must be offset by this count to align with the correct factory.
*/
function getHydrationIndexOffset(factories: CompiledViewBehaviorFactory[]): number {
let offset = 0;

Expand Down
Loading
Loading