Skip to content

feat(press): add compile-time named regions - #484

Merged
Mohamed Mansour (mohamedmansour) merged 7 commits into
microsoft:mainfrom
mohamedmansour:mohamedmansour-press-named-regions
Aug 25, 2026
Merged

Mohamed Mansour (mohamedmansour) merged 7 commits into
microsoft:mainfrom
mohamedmansour:mohamedmansour-press-named-regions

Conversation

@mohamedmansour

@mohamedmansour Mohamed Mansour (mohamedmansour) commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add reusable compile-time <webui-press-region> extension points with template fallback content and optional config overrides
  • expose 17 stable built-in regions across site navigation, home, documentation, wide-page, and full layouts
  • inject layout-scoped HTML, namespaced state, discovered components, and explicit scripts before protocol compilation, including doc-scoped 404 handling
  • document the regions configuration contract while preserving --template as the full-replacement escape hatch

Scope

This PR exposes only the generalized WebUI Press region architecture. It intentionally excludes consumer-specific docs wiring, Benchmark Explorer content/state, benchmark publication, ssr-framework-bench, framework/router performance work, and manifest or lockfile changes.

Validation

  • cargo test -p microsoft-webui-press
  • real scratch Press builds proving layout-scoped fallback and override HTML, SSR components, namespaced state, scoped scripts, and doc-scoped 404 output
  • real docs build plus Playwright geometry checks for home/doc/full layouts, announcement height, and replacement navigation height
  • cargo xtask check

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ce183264-ef7d-439f-b9c4-06720fe7e704
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ce183264-ef7d-439f-b9c4-06720fe7e704
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ce183264-ef7d-439f-b9c4-06720fe7e704

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a compile-time “named regions” extension mechanism to WebUI Press templates (<webui-press-region>), allowing sites to override or augment specific layout-scoped portions of the bundled template (HTML, state, and optional scripts) prior to component discovery and protocol compilation.

Changes:

  • Introduces region parsing/rendering (RegionSet) with config-backed HTML/state/script overrides and layout scoping.
  • Wires regions into the Press build pipeline: component discovery, per-page explicit scripts, state namespacing under reserved regions, and doc-scoped 404 handling.
  • Updates bundled template, CSS layout, and documentation (DESIGN + README) to expose and describe 17 stable built-in regions.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
DESIGN.md Documents the compile-time named regions contract and stability guarantees.
crates/webui-press/template/index.ts Removes hard-coded component import; relies on region-driven component discovery.
crates/webui-press/template/index.html Wraps navigation/home/doc/full/page sections in <webui-press-region> markers (17 stable regions).
crates/webui-press/template/docs.css Adjusts layout to flex column so region-wrapped nav + content sizing remains correct.
crates/webui-press/src/types.rs Adds DocsConfig.regions and the RegionConfig schema.
crates/webui-press/src/state.rs Reserves regions in render state and exposes StateLoader for region state loading.
crates/webui-press/src/regions.rs Implements RegionSet (load, render, state injection, script discovery).
crates/webui-press/src/regions/parser.rs Adds strict scanner for <webui-press-region> declarations.
crates/webui-press/src/regions/tests.rs Adds coverage for region rendering, stable region inventory, state namespacing, and validation errors.
crates/webui-press/src/build.rs Integrates regions into build: component/script discovery, state injection, page rendering, and 404 generation.
crates/webui-press/src/main.rs Registers the new regions module in the binary crate.
crates/webui-press/src/lib.rs Registers the new regions module in the library crate.
crates/webui-press/README.md Documents region authoring/configuration and lists built-in stable regions.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/webui-press/src/regions.rs
Comment thread crates/webui-press/src/regions/parser.rs Outdated
Comment thread crates/webui-press/src/types.rs Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ce183264-ef7d-439f-b9c4-06720fe7e704

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread crates/webui-press/src/regions/parser.rs
Comment thread crates/webui-press/README.md
Comment thread crates/webui-press/src/build.rs
Comment thread crates/webui-press/src/build.rs Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ce183264-ef7d-439f-b9c4-06720fe7e704

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.

Comment thread docs/guide/webui-press.md Outdated
Comment thread crates/webui-press/src/regions/parser.rs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ce183264-ef7d-439f-b9c4-06720fe7e704
@mohamedmansour
Mohamed Mansour (mohamedmansour) merged commit 19445f1 into microsoft:main Aug 25, 2026
24 checks passed
@mohamedmansour
Mohamed Mansour (mohamedmansour) deleted the mohamedmansour-press-named-regions branch August 25, 2026 17:15
Mohamed Mansour (mohamedmansour) added a commit that referenced this pull request Aug 25, 2026
## Summary

- remove hydrated conditional comment anchors while their bodies are
visible
- create an empty anchor only while a conditional body is absent, then
remove it when content returns
- swap ownership ranges only across the contiguous ancestor chain
sharing the live DOM container
- skip owner compaction for fixed-shape conditional bodies; retain it
only when root structural metadata permits deferred-mount snapshots to
diverge
- document the exact marker lifecycle and cover SSR/client
hide-show-hide, empty bodies, nested teardown, keyed/nested repeats,
adjacent repeats, text-only ranges, and deferred snapshot cleanup

## Algorithm

`CondBinding` keeps `anchor: null` while visible and one comment while
absent. `$swapOwnedRange` identifies the current Node or contiguous Node
array by first/last identity, then updates only `TemplateInstance.nodes`
arrays whose `container` is the range's parent. This is the complete
possible owner set: once an ancestor has another container, a static DOM
boundary prevents higher instances from directly owning that range.

The implementation intentionally avoids persistent `Range` objects,
per-node maps/indexes, linked ownership segments, recursion, and
per-update owner-array rebuilds. Existing cursor insertion remains the
DOM mutation path; the helper only maintains the direct node arrays
required by keyed-repeat moves.

A deferred stylesheet mount can resnapshot a root while a top-level
nested repeat later grows. Those compiler-identifiable root structural
blocks retain post-removal compaction; fixed-shape leaf conditions avoid
that walk. The regression recreates the resnapshot/growth case and fails
by retaining the disconnected fifth item when the guard is removed.

## Performance

Measured against refreshed `origin/main` at `e6ad166b` (including #482
and #484). Baseline and branch used identical fixture source.

### Transition latency

The final timing-only capture ran in an exclusive benchmark slot.
Baseline and branch servers ran concurrently with one Chromium process.
For each scale and variant, 20 fresh-page blocks contributed five
measured hide/show cycles each: **100 samples per variant**. Block order
alternated baseline → branch and branch → baseline; every block ran
three warm cycles and two forced garbage collections before measurement.

| Items | Hide P50 / P95 | Show P50 / P95 | Paired hide+show P50 / P95 |
| ---: | ---: | ---: | ---: |
| 1,000 | 5.7 / 6.7 ms → 4.0 / 4.8 ms | 8.5 / 11.9 ms → 9.1 / 12.5 ms |
14.5 / 17.1 ms → **12.9 / 15.8 ms** |
| 5,000 | 109.4 / 116.7 ms → 52.0 / 67.1 ms | 31.3 / 41.8 ms → 34.1 /
43.2 ms | 141.3 / 157.6 ms → **86.7 / 107.7 ms** |
| 10,000 | 450.4 / 476.4 ms → 191.0 / 343.2 ms | 61.2 / 80.9 ms → 63.9 /
83.2 ms | 514.8 / 544.7 ms → **255.3 / 424.4 ms** |

Show-only transitions pay the temporary-anchor removal cost: P50/P95
regress **7.1% / 5.0%**, **8.9% / 3.3%**, and **4.4% / 2.8%** at 1,000 /
5,000 / 10,000 items. Hide improves enough that the complete paired
cycle improves **11.0% / 7.6%**, **38.6% / 31.7%**, and **50.4% /
22.1%** respectively.

Counterbalanced paired-block median ratios corroborate the raw samples.
For the complete cycle, branch/baseline P50/P95 ratios are **0.897 /
0.929**, **0.613 / 0.653**, and **0.494 / 0.508**; even the
95th-percentile block ratio stays below 1 at every scale.

### DOM and retained heap

Twenty counterbalanced fresh-page samples per variant and scale used two
`HeapProfiler.collectGarbage` calls before `Runtime.getHeapUsage`;
retained heap is V8 `usedSize + embedderHeapUsedSize`.

| Items | Visible conditions | DOM nodes | Comments | Forced-GC retained
heap P50 | Delta |
| ---: | ---: | ---: | ---: | ---: | ---: |
| 1,000 | 3,000 | 8,008 → 5,008 | 3,003 → 3 | 6,819,444 B → 6,502,756 B
| **-316,688 B (-4.64%)** |
| 5,000 | 15,000 | 40,008 → 25,008 | 15,003 → 3 | 26,588,504 B →
24,972,728 B | **-1,615,776 B (-6.08%)** |
| 10,000 | 30,000 | 80,008 → 50,008 | 30,003 → 3 | 51,241,528 B →
48,007,284 B | **-3,234,244 B (-6.31%)** |

The embedder reduction is exactly 88 B per released comment in these
captures: -264,000 B / -1,320,000 B / -2,640,000 B. V8 heap also falls
by 52,624 B / 295,776 B / 594,244 B.

The refreshed production framework bundle changes from 77,783 B / 24,384
B gzip to 78,399 B / 24,612 B gzip (**+616 B / +228 B gzip**).

## Validation

- framework typecheck
- focused conditional, text-only, keyed/nested-repeat, and
structural-order Playwright coverage
- regression proven to fail without guarded compaction
- full framework suite: 323 unit tests passed; 266 Playwright tests
passed, 2 skipped
- final specialist code review: no findings
- post-rebase `cargo xtask check`

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b71de2e-345c-46b5-bfab-c8a8c126428e
Mohamed Mansour (mohamedmansour) added a commit that referenced this pull request Aug 26, 2026
## Release

Bumps WebUI to `0.0.26`.

Previous release tag: `v0.0.25`

## Changes since `v0.0.25`

Features:

- Python hosts now have an official typed PyO3 renderer package with
buffered, partial, template, token, and host-driven streaming APIs
(feat: add official Python renderer package #453 by @mohamedmansour).
- Progressive SSR can place transport-flushed streaming boundaries
inside reusable components while preserving component ownership and
continuation state (feat: support component-local streaming boundaries
#460 by @mohamedmansour).
- Components can defer compiler-owned hydration until interaction, with
router preload handoff and a combined lazy-render policy (feat: add
compiler-driven interaction hydration #485 by @mohamedmansour).
- Builds can opt into global Light DOM CSS while preserving explicit
authored Shadow roots and deterministic style closures (feat: make Light
DOM a global CSS opt-in #429 by @mohamedmansour).
- State projection supports application-owned TypeScript 7.0.2 while
retaining the TypeScript 6 migration path (feat: support TypeScript 7
projection compilation #452 by @mohamedmansour).
- WebUI Press supports layout-scoped compile-time named regions with
fallback HTML, state, components, and scripts (feat(press): add
compile-time named regions #484 by @mohamedmansour).
- FAST v2 and v3 gain plugin-owned local and npm component discovery
with validated FAST template transformation (feat: add plugin-owned FAST
component discovery #378 by @janechu).

Fixes:

- Missing condition identifiers are treated as falsy before negation and
logical evaluation, aligning SSR with the browser runtime (fix: negate
missing condition paths correctly #449 by @mohamedmansour).
- FAST route state now scales through escaped scalar kebab-case
attributes shared by FAST v2 and v3 (fix: scale FAST route state with
scalar attributes #450 by @janechu).
- Dynamic Link-mode components wait for native stylesheet readiness
across navigation and component assets, preventing unstyled flashes
(fix: prevent dynamic component stylesheet flashes #454 by
@mohamedmansour).
- Authored component definitions defer whenever compiled template
metadata has not arrived, including ordinary router navigation (fix:
defer authored define() whenever template metadata is missing #461 by
@mohamedmansour).
- Client structural updates preserve authored order and sibling
ownership for shared slots and raw HTML ranges (fix: preserve source
order for shared structural slots #465 by @mohamedmansour, fix: preserve
siblings around raw HTML updates #466 by @mohamedmansour).
- Native-element attributes no longer leak into the local state of a
later component (perf(handler): stop native attributes leaking into
component state #469 by @mohamedmansour).
- Templates-and-state-only SSR bootstrap payloads no longer require
component style metadata (fix: allow SSR bootstrap without component
styles #475 by @mohamedmansour).
- The high-level Rust `serve_request` path now preserves complete render
options, including CSP nonces, while sharing the same entry and request
path with partial rendering (fix: forward CSP nonces through
serve_request #488 by @mohamedmansour).
- Projection compilation bounds source reads, excludes binary and
unsupported-loader inputs from semantic analysis, and preserves
deterministic cleanup under large esbuild graphs (fix: bound projection
adapter source reads #489 by @mohamedmansour).
- Router pending UI remains mounted through pre-commit work and settles
at the synchronous DOM commit, with stale, aborted, and re-entrant
navigation cleanup kept generation-safe (fix: settle router pending UI
during navigation commits #491 by @mohamedmansour).

Docs:

- The documentation site adds accessible responsive navigation, improved
reading layouts, stronger search behavior, and Playground recovery
states (feat: polish WebUI documentation experience #459 by
@mohamedmansour).
- Slot-resolution implementation guidance now documents pre-order
lookup, pending placement ownership, and marker handling (chore: clarify
slot resolution comments #471 by @mohamedmansour).
- Repeated `w-ref` behavior is now explicit: refs are scalar and the
last wired occurrence wins, while stable authored IDs or item components
provide identity-based lookup (chore: clarify repeated w-ref behavior
#490 by @mohamedmansour).

Maintenance:

- Release and package policy metadata now constrains the transitive h2
advisory, uses SPDX NuGet licensing, and classifies publishing jobs
correctly (chore: allow constrained h2 advisory #451 by @janechu, fix:
use modern NuGet license metadata #457 by @janechu, chore: mark
publishing jobs as release jobs #458 by @janechu).
- The development and CI Rust toolchain is updated to 1.98 with the
resulting warnings resolved (Update rust toolchain version and fix
clippy warning #462 by @telecos).
- Release builds use Thin LTO to retain cross-crate optimization with
faster linking (perf: switch release builds to Thin LTO #464 by
@mohamedmansour).
- Handler and expression hot paths reduce attribute vtable calls, render
lookup and scope allocations, and single-term condition overhead
(perf(handler): centralize HTML attribute writing in ResponseWriter #467
by @mohamedmansour, perf(expressions): fast-path single-term conditions
#470 by @mohamedmansour, perf(handler): reduce render lookup and scope
allocations #472 by @mohamedmansour).
- Node rendering can reuse immutable prepared-state snapshots and
bounded per-route output capacity hints (perf(node): reuse prepared
state across renders #477 by @mohamedmansour, perf: reuse Node render
output capacity #478 by @mohamedmansour).
- Framework hydration releases bootstrap data sooner and reduces
allocations for bindings, empty hosts, and visible conditionals (perf:
reduce framework hydration allocations #479 by @mohamedmansour, perf:
release SSR bootstrap memory after hydration #480 by @mohamedmansour,
perf: reduce empty template host overhead #482 by @mohamedmansour, perf:
remove visible conditional anchors #483 by @mohamedmansour).
- Benchmark tooling now renders the full contact workload, runs
Criterion baselines per target, and restores the streaming hydration
fixture (fix(bench): render contacts in contact-book benchmark #468 by
@mohamedmansour, fix(xtask): run Criterion benchmarks per target #473 by
@mohamedmansour, fix: repair streaming hydration benchmark fixture #476
by @mohamedmansour).

## Validation

- `cargo xtask check`

---------

Co-authored-by: Copilot App <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.

3 participants