Skip to content

Switch default styles to module for commerce demo#327

Merged
mohamedmansour merged 6 commits into
mainfrom
users/kschmi/commerce-default-css-module
Jun 6, 2026
Merged

Switch default styles to module for commerce demo#327
mohamedmansour merged 6 commits into
mainfrom
users/kschmi/commerce-default-css-module

Conversation

@KurtCattiSchmidt

Copy link
Copy Markdown
Contributor

No description provided.

KurtCattiSchmidt and others added 6 commits June 5, 2026 16:20
… in `style-src`

Two coupled tweaks so the commerce demo exercises the new CSS-modules-
via-importmap shape out of the box:

1. Flip `start:server` from `--css=link` to `--css=module` so
   `pnpm start` (and `cargo xtask dev commerce`) brings up the demo
   using the new shape by default. Reviewers can flip back to `link`
   to compare.

2. Add `data:` to `style-src` in the demo CSP. The new shape imports
   component CSS via `data:text/css,…` URIs referenced from
   `<script type="importmap">`. Without `data:` in
   `style-src`/`style-src-elem` the browser blocks the import. Worth
   noting in the upstream PR: apps adopting the importmap shape must
   allow `data:` in `style-src` — a strictly broader policy than the
   `<style type="module" nonce="…">` shape required.
…lates for CssStrategy::Module

For CssStrategy::Module the framework owns CSS adoption — the
shadowrootadoptedstylesheets attribute is the only wire connecting
the importmap specifier to the shadow root. Previously, when a developer
supplied their own <template> wrapper (typically to attach @event
handlers, as mp-app does), process_component_template intentionally
dropped the framework-injected attribute under the assumption that
"dev owns the wrapper, dev owns adoption." That assumption is wrong:
the importmap is emitted by the framework regardless, so dropping the
attribute silently breaks CSS module adoption for any component that
authors its own template.

This caused the commerce Playwright visual regressions on /search*:
mp-app''s `* { box-sizing: border-box }` reset never adopted, so
mp-page-search''s `:host { display: flex; padding: 0 1rem; max-width:
96rem }` overflowed by 32px.

Fix: inject `shadowrootadoptedstylesheets="<tag>"` into the dev''s
opening tag whenever adopted_specifier is Some and the dev has not
already written one (multi-specifier scenarios honored verbatim). Uses
the quote-aware tag_scan::find_tag_close so attribute values
containing `>` are handled correctly.

Mirror the dedup check in plugin/fast_v2.rs and plugin/fast_v3.rs
so the f-template (client-hydration) path agrees with SSR when a dev
template carries an existing shadowrootadoptedstylesheets attribute.

Updates DESIGN.md to document framework ownership of CSS adoption
in Module strategy and adds 4 regression tests covering injection,
attribute preservation, multi-specifier honor, and the no-op when
adopted_specifier is None.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rappers under --css=module

The previous commit auto-injected the framework-derived specifier when a
developer-authored <template> wrapper omitted it. Per PR review, silently
overwriting attributes on a wrapper the developer owns is the wrong default;
fail fast instead with an actionable error.

Changes:
* Add ParserError::MissingAdoptedStylesheets variant whose message names the
  offending component, supplies a copy-pasteable attribute, and points at the
  opt-out (remove the <template> wrapper to let the framework manage it).
* process_component_template and build_component_template now return Result and
  validate the dev-supplied wrapper at parse time. The multi-specifier opt-out
  (any value containing the component tag, e.g. "mp-app theme") still passes.
* Revert auto-injection in fast_v2 / fast_v3 plugin paths; under the new rule
  the parser pass guarantees a valid wrapper before plugin emission runs, so
  these branches just preserve the developer template verbatim.
* Declare shadowrootadoptedstylesheets="mp-app" on the commerce mp-app
  organism, the only example currently consuming --css=module with a
  developer-authored wrapper.
* Update DESIGN.md (Module strategy contract) and docs/guide/cli to describe
  the new build-time requirement and the opt-out path.

Existing dev-template tests adapted to the Result signature; new tests cover
the error path, the actionable-message contents, the success path when the
attribute is present, multi-specifier values, and the no-validation case when
no CSS module is associated with the component.

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

The Module CSS strategy emits <style type="module" specifier="..."> alongside
shadowrootadoptedstylesheets on declarative shadow roots. This wiring relies
on the Declarative CSS Modules proposal, which currently ships behind the
DeclarativeCSSModules Blink feature flag in Chromium.

Without the flag the browser never registers the module-script style elements
and never adopts them onto the declarative shadow roots, so every component
renders unstyled. Mirror the launch args already set in
packages/webui-framework/playwright.config.ts so the commerce demo (now
defaulting to --css=module) exercises the feature path under test.

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

Chromium 145+ enforces script-src for <style type="module"> elements because they affect the module map. PR #292 added the nonce on the initial SSR path but explicitly deferred the SPA partial-navigation case to avoid changing render_partial/render_component_templates signatures (which would cascade into FFI/Node/WASM/CLI bindings).

This completes the follow-up on the client side: when registerTemplatesAndStyles re-injects a <style type="module"> from the JSON partial, apply the page's existing nonce (window.__webui.nonce). No server signature change required — the page's CSP already allows this nonce.

Without this fix, every SPA navigation that pulls in new component CSS triggers `Executing inline script violates Content Security Policy directive 'script-src ...`'' and the styles never adopt, leaving newly-loaded components unstyled.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# Conflicts:
#	DESIGN.md
#	docs/guide/cli/index.md
#	packages/webui-router/src/router.test.ts
#	packages/webui-router/src/templates.ts
@mohamedmansour mohamedmansour merged commit 88fc307 into main Jun 6, 2026
21 checks passed
@mohamedmansour mohamedmansour deleted the users/kschmi/commerce-default-css-module branch June 6, 2026 02:40
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>
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