Skip to content

chore(fast-html): use @microsoft/fast-build to build when fixture with lowercase attrs#7380

Merged
janechu merged 9 commits intomainfrom
users/janechu/update-fixture-to-use-fast-build-when
Apr 8, 2026
Merged

chore(fast-html): use @microsoft/fast-build to build when fixture with lowercase attrs#7380
janechu merged 9 commits intomainfrom
users/janechu/update-fixture-to-use-fast-build-when

Conversation

@janechu
Copy link
Copy Markdown
Collaborator

@janechu janechu commented Apr 4, 2026

Pull Request

📖 Description

Adds the when test fixture to the @microsoft/fast-html package's build-fixtures.js script so it is generated by @microsoft/fast-build SSR alongside the existing attribute, binding, event, ref, and slotted fixtures.

This PR also includes a fix to @microsoft/fast-build where entry-level root custom elements now merge the full root state with their own per-element attribute-derived state when rendering their shadow template. Previously, entry elements received only the full root state, which broke elements whose template expressions depend on per-element HTML attributes (e.g. planet="earth", vara="3", boolean show). Attribute-derived values take precedence over root state for overlapping keys.

The nested-when template expressions are updated to use camelCase identifiers (showProgress, enableContinue) matching both the state.json keys and the element's @observable property names, ensuring correct server-side resolution and correct FAST hydration binding.

📑 Test Plan

All existing Rust unit tests pass (cargo test in crates/microsoft-fast-build). Fixture output verified by running npm run build:fixtures — only the when fixture changed (no regressions in attribute, binding, event, ref, or slotted fixtures). The when/when.spec.ts Playwright tests cover the full lifecycle: initial SSR state, FAST hydration, and reactive property changes.

✅ Checklist

General

  • I have included a change request file using $ npm run change
  • I have added tests for my changes.
  • I have tested my changes.
  • I have updated the project documentation to reflect my changes.
  • I have read the CONTRIBUTING documentation and followed the standards for this project.

@janechu
Copy link
Copy Markdown
Collaborator Author

janechu commented Apr 6, 2026

Updated to pass state attributes to the nested-when element. Now builds successfully with the renderer fix in #7396 (kebab-to-camelCase attribute mapping).

@janechu janechu marked this pull request as ready for review April 6, 2026 23:55
@janechu janechu force-pushed the users/janechu/update-fixture-to-use-fast-build-when branch from 8e19d1e to 6149a56 Compare April 7, 2026 02:56
@janechu janechu changed the title chore(fast-html): use @microsoft/fast-build to build when fixture chore(fast-html): use @microsoft/fast-build to build when fixture with lowercase attrs Apr 7, 2026
@janechu janechu marked this pull request as draft April 7, 2026 21:47
@janechu janechu force-pushed the users/janechu/update-fixture-to-use-fast-build-when branch from 6149a56 to dec13fa Compare April 7, 2026 21:52
@janechu janechu marked this pull request as ready for review April 7, 2026 21:55
@janechu janechu requested a review from Copilot April 7, 2026 22:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the @microsoft/fast-html fixture build pipeline to include the when fixture in SSR generation via @microsoft/fast-build, and adjusts microsoft-fast-build so entry-level (root) custom elements can render shadow templates using both root state and per-element attribute-derived state.

Changes:

  • Add the when fixture to packages/fast-html/scripts/build-fixtures.js and introduce when fixture inputs (entry.html, templates.html, state.json) + regenerated index.html.
  • Change microsoft-fast-build root custom element rendering to merge root JSON state with attribute-derived state for shadow template evaluation.
  • Update microsoft-fast-build documentation (README + DESIGN) to describe merged-state behavior for entry rendering.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/fast-html/test/fixtures/when/templates.html New <f-template> declarations for the when fixture used by fixture injection/hydration.
packages/fast-html/test/fixtures/when/state.json New fixture state used for SSR generation.
packages/fast-html/test/fixtures/when/main.ts Defines the fixture custom elements used by the templates/tests.
packages/fast-html/test/fixtures/when/index.html Regenerated SSR output + injected templates for the fixture page.
packages/fast-html/test/fixtures/when/entry.html New entry HTML input used by fast-build to generate the fixture SSR output.
packages/fast-html/scripts/build-fixtures.js Adds when to the list of fixtures rendered via @microsoft/fast-build.
crates/microsoft-fast-build/src/directive.rs Implements merged root+attribute state for entry-level custom elements.
crates/microsoft-fast-build/README.md Updates docs to explain merged-state behavior and root-element attribute handling.
crates/microsoft-fast-build/DESIGN.md Updates design notes for is_entry semantics to match merged-state behavior.
change/@microsoft-fast-html-when-00615379-81a9-4dd0-86af-bd600a8ab155.json Records the @microsoft/fast-html change entry.
Comments suppressed due to low confidence (1)

crates/microsoft-fast-build/src/directive.rs:285

  • build_attr_state currently skips all attributes that start with ?. That avoids mis-resolving expressions like ?disabled="{{!enableContinue}}", but it also means ?attr boolean bindings on a custom element tag can never influence the element’s shadow-template rendering state (even though entry-tag rendering does evaluate ?attr). Consider evaluating ?attr="{{expr}}" with evaluate() and inserting a boolean into the child state (under the attr name without ?), so SSR state and rendered HTML stay consistent.
        let attrs = parse_element_attributes(open_tag_content);
        let mut state_map = base.unwrap_or_default();
        for (attr_name, value) in &attrs {
            // Skip @event handlers — they are client-side only and have no meaning in SSR state.
            // Also skip f-ref, f-slotted, f-children, and ?boolean-binding directives — all are
            // resolved entirely by the FAST client runtime.
            if attr_name.starts_with('@')
                || attr_name.starts_with('?')
                || attr_name.eq_ignore_ascii_case("f-ref")
                || attr_name.eq_ignore_ascii_case("f-slotted")
                || attr_name.eq_ignore_ascii_case("f-children")
            {
                continue;
            }

janechu and others added 8 commits April 7, 2026 15:49
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use lowercase no-dash attribute names (e.g. vara, thisvar, thatvar,
showprogress, enablecontinue) to match the SSR crate's lowercasing
behaviour and to avoid hyphen-separated state keys that would not
match the camelCase template expressions.

- main.ts: update @attr declarations to use no-dash attribute names
- entry.html: replace dash-case attrs with lowercase no-dash equivalents
- templates.html: update f-when expressions to use lowercase state keys
- index.html: regenerated via npm run build:fixtures

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously, entry-level root elements received only the full root
state for child rendering. This broke elements with per-element
attribute state (e.g. planet="earth", vara="3", boolean show)
because those values were not present in the shared root state.json.

Now entry elements start with the root state as a base and overlay
their own attribute-derived values on top. This ensures both
app-level context (error, showProgress) and per-element attributes
(planet, vara, show) are available to the shadow template.

Also update the nested-when template to use camelCase expressions
(showProgress, enableContinue) matching the state.json keys and
the element's @observable property names for correct FAST hydration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Entry custom elements now receive root state merged with their own
attribute-derived state, rather than only the full root state.
Update docs to reflect the new behaviour and corrected table/examples.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
FAST template bindings resolve against JS property names at hydration
time. Rename varA→vara and thisVar/thatVar→thisvar/thatvar so the
{{vara}}, {{thisvar}}, {{thatvar}} expressions in templates.html match
the actual observable properties and react correctly after hydration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add five tests covering the new merge behaviour for entry-level custom
elements: per-element attr available in template, attr overrides
matching root key, root keys still accessible alongside attr, boolean
attr resolves to true, and multiple root elements each with independent
per-element attr values.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@janechu janechu force-pushed the users/janechu/update-fixture-to-use-fast-build-when branch from 8a9e36e to 937ef5d Compare April 7, 2026 22:51
Add scope_prefix to HydrationScope so that f-when bodies produce
marker IDs that are globally unique within a shadow DOM.

Previously, render_when created a fresh child scope starting from 0,
so a nested f-when produced the same marker (e.g. "when-1") as the
outer f-when at the same index. The FAST client runtime scans siblings
linearly for end markers by ID, so it matched the inner end marker
first, giving the outer when-1 a truncated content range.

Fix: child(parent_idx) now prefixes inner marker names with the
parent's allocated index (e.g. "1-"), yielding "1-when-0" and
"1-when-1" inside the outer when-1 body. The outer end-marker search
for "when-1" no longer finds a false match, so the correct DOM range
is captured and reactive updates work properly.

All Rust tests pass (190 tests). Fixture index.html regenerated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@janechu janechu merged commit 3a15f54 into main Apr 8, 2026
14 checks passed
@janechu janechu deleted the users/janechu/update-fixture-to-use-fast-build-when branch April 8, 2026 01:45
janechu added a commit that referenced this pull request Apr 8, 2026
Regenerate repeat/index.html after rebasing onto main (which includes
PR #7403 entry-attribute stripping and PR #7380 when fixture).

Changes reflect correct entry-element behavior:
- Non-primitive binding attrs (list, someData) stripped from opening tag
- test-element-no-item-repeat-binding now renders empty repeat since
  list="{{emptyList}}" overrides root list with [] in merged state

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
janechu added a commit that referenced this pull request Apr 8, 2026
Regenerate repeat-event/index.html after rebasing onto main (which
includes #7381 repeat fixture, #7380 when fixture, and #7403
entry-attribute stripping).

Non-primitive binding attrs (items) are now stripped from entry element
opening tags; primitive attrs (show-names="true") are preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants