Emit style modules via importmap + dataURI instead of <style type="module">#325
Merged
Merged
Conversation
…URIs
Replace the per-component `<style type="module" specifier="X">CSS</style>`
emission with `<script type="importmap">{"imports":{"X":"data:text/css,…"}}</script>`.
Why
---
The `<style type="module">` shape is a non-standard CSS-module-style-tag
prototype that has not shipped in all host browsers Edge serves built-in
WebUIs in. Import Maps + `data:text/css,…` URIs achieve the same end —
the browser resolves a CSS module by specifier — using only standards-
track features available in Chrome 133+.
The shape change is transparent to downstream consumers: the framework's
client-side adoption code resolves CSS modules by specifier the same way
in both forms, and `adoptedStyleSheets` continues to work unchanged.
What changed
------------
* New private method `emit_css_module_importmap(specifier, css, ctx)`
in `crates/webui-handler/src/lib.rs`. Percent-encodes only the bytes
that would actually mis-parse in a data URI (`%` `#` `"` whitespace
control chars, non-ASCII) — keeps human-readable CSS readable in
DevTools' importmap view.
* Builds the JSON body with `serde_json::json!` so the specifier and
data URI are always correctly JSON-escaped.
* Both emission call sites — `emit_css_module` (per-component first
render) and the `body_end` reachable-but-unrendered loop — route
through the new helper.
* CSP nonce is applied identically to the legacy `<style type="module">`
path and to the bootstrap `<script>` emit, so the existing nonce
tests stay green (assertions updated to the new emission shape).
* Tests updated: positive-shape asserts now check for
`<script type="importmap"…>` and the embedded data URI; negative-
shape asserts in non-module strategies additionally guard against
accidental importmap emission.
Tests
-----
`cargo test -p microsoft-webui-handler --lib` — 285/285 pass.
`cargo test --workspace --lib` — all crates green.
e4f9826 to
b40946e
Compare
mohamedmansour
approved these changes
Jun 6, 2026
mohamedmansour
added a commit
that referenced
this pull request
Jun 8, 2026
Clusters: - feat: parser comment policy strips template/style comments while preserving legal comments, with CLI, Node, docs, and benchmark coverage (#326, b513efb). - feat: CSS module delivery now emits import-map data URI modules and the commerce demo defaults to module styles (#325, #327, f5cedc3, 88fc307). - fix: repeat-scope event arguments hydrate correctly for framework bindings, including strict argument handling (#317, #322, 11b6a6d, c0bd525). - fix: client binding lifecycle ordering preserves child updates across conditional and repeated DOM paths (#329, 0f40666). - fix: compiled templates preserve raw style text instead of altering author-provided CSS content (#330, 4db730a). - docs: issue forms, contribution/support policy, framework rendering docs, CLI docs, and integration guides were refreshed (#321, #328, plus docs in #322/#325/#326/#329; 6853b4c, f97bdc6). Release bump: - Update Rust workspace crates, internal crate dependency constraints, Cargo.lock package versions, npm packages, platform packages, router/framework/test-support packages, and .NET Directory.Build.props from 0.0.14 to 0.0.15. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
<style type="module">is going to need some spec updates and will probably have some syntax changes before we can ship it. In the meantime, we can simulate it via an Import Map and a dataURI. Performance characteristics are very similar between the two, with small stylesheets and duplicated stylesheets actually being slightly faster than<style type="module">.This change updates the Rust BTR code with the "module" strategy to output an equivalent Import Map instead of
<style type="module">. Theserde_jsonRust library is used for JSON handling, which is used elsewhere in WebUI, so this is not a new dependency.e.g. this:
...would be replaced by:
...where the CSS content is URL-encoded in the Import Map version. This depends on Multiple Import Map support, which was enabled in Chromium 133. Mozilla and WebKit have positive support for Multiple Import Maps but haven't shipped it yet. Since the "module" strategy also depends on
shadowrootadoptedstylesheetssupport (which hasn't shipped yet), it should be fine to add this new dependency.