Skip to content

feat: add automatic HTML-only WebUI elements#377

Open
mohamedmansour wants to merge 7 commits into
mainfrom
mohamedmansour-interactive-islands-test
Open

feat: add automatic HTML-only WebUI elements#377
mohamedmansour wants to merge 7 commits into
mainfrom
mohamedmansour-interactive-islands-test

Conversation

@mohamedmansour

@mohamedmansour mohamedmansour commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

HTML-only WebUI components currently need empty WebUIElement stubs just to preserve SSR state and accept router-driven updates. This adds compiler-marked auto-elements so declarative components can omit .ts files while still hydrating, observing attributes, and supporting setState() when the framework needs to update them.

Approach

  • Teach the WebUI parser to detect sibling component scripts and emit ae:1 only for filesystem-discovered .html components without sibling .ts / .js implementations.
  • Install the auto-element runtime from the framework root entrypoint, so apps do not call installAutoElementRuntime(...) or maintain manual tag lists.
  • Split the static CoreElement path from interactive WebUIElement features so HTML-only components avoid event/ref/emit code when it can be tree-shaken.
  • Keep webui-router platform-independent by dispatching template-registration events instead of importing framework code.
  • Harden lazy-loader ownership with blockedTags so loader-owned tags are never auto-claimed before authored modules define them.
  • Skip auto-upgrading fully static scriptless templates; they stay plain SSR DOM with no custom-element runtime cost.
  • Remove declarative-only component stubs from contact-book, commerce, calculator, routes, and component-assets examples.

Review notes

The initial page auto-claim is deferred by one microtask so authored custom elements and router loader exclusions can register first. Router partial/template registrations still claim eligible templates synchronously after new template metadata arrives, before passive router stubs are needed.

Event wiring now uses delegated event buckets, with one listener per event name on the component render root and per-instance cleanup for removed conditional/repeat blocks. Complex : child bindings now fall back to direct property assignment when a child WebUI element does not handle the key through decorated or template-only state, preserving authored non-observable setters.

Bundle size

A follow-up cleanup removed compatibility-oriented delegated-event fallback code, reused the existing template-root analysis instead of shipping a second dynamic-template scanner/cache, and collapsed template-registration parsing.

Measured probe deltas from before the cleanup to after:

Probe Minified Gzip Brotli
Root import 27,812 -> 27,523 B 9,229 -> 9,190 B 8,258 -> 8,243 B
Authored component 32,089 -> 31,452 B 10,579 -> 10,441 B 9,469 -> 9,353 B

Validation

  • cargo check
  • cargo xtask check
  • pnpm --filter @microsoft/webui-framework typecheck
  • pnpm --filter @microsoft/webui-framework test:unit
  • pnpm --filter @microsoft/webui-framework typecheck:e2e
  • playwright test tests/fixtures/optional-template-state tests/fixtures/repeat-conditional
  • pnpm --filter @microsoft/webui-router typecheck
  • pnpm --filter @microsoft/webui-router test
  • cargo test -p microsoft-webui-parser --lib
  • cargo check -p microsoft-webui-parser --no-default-features

Additional note: cargo xtask e2e was run earlier; the functional suites passed, while existing visual screenshot baselines in contact-book/commerce and webui-press readiness checks still reported diffs/timeouts for separate follow-up.

mohamedmansour and others added 7 commits June 30, 2026 18:44
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep delegated event dispatch on the shared handler invocation path while exposing the bound element as event.currentTarget for handlers that receive e.

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.

1 participant