Skip to content

[devtools-extension] fix panel CSS, dedupe rules, add metadata export#1721

Merged
mellyeliu merged 2 commits into
mainfrom
devtools-extension-metadata-export-and-fixes
Jun 16, 2026
Merged

[devtools-extension] fix panel CSS, dedupe rules, add metadata export#1721
mellyeliu merged 2 commits into
mainfrom
devtools-extension-metadata-export-and-fixes

Conversation

@mellyeliu

@mellyeliu mellyeliu commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary

A few fixes and one new feature for the StyleX DevTools extension.

Fix: panel renders with no styles (when built from current main)

panel.html has a hardcoded <link href="./assets/style.css">. At build time two things feed that asset:

  1. The custom cssBundle rollup plugin emits the imported index.css (reset) as assets/style.css.
  2. The StyleX unplugin merges all StyleX-generated atomic CSS into that .css asset.

This used to work: when the extension was added (#1401), the unplugin merged its CSS in place, keeping the filename style.css, so the <link> resolved. The currently-published Store build predates the change below and is styled correctly.

Since #1444 ("[unplugin] Bun support and refactor"), the unplugin emits a new asset for the merged CSS instead of editing in place. Because assetFileNames has no content hash and style.css is already taken by step 1, Rollup deduplicates the new file to style2.css and deletes the original. The unplugin rewrites references inside the JS bundle, but panel.html is a static file copied verbatim (not part of the bundle), so its link still pointed at style.css → 404 → the panel loaded completely unstyled.

The copy-static plugin now reads the actual emitted CSS filename from the bundle and rewrites the stylesheet href in copied HTML to match (name-agnostic, so it works for style.css, style2.css, or hashed names).

Fix: duplicate declaration rows

collectStylexDebugData walked every stylesheet and pushed a row per matching rule occurrence. When an identical atomic rule was injected into multiple stylesheets (common in dev: HMR re-injection, React StrictMode, multiple bundles) the same declaration rendered 2–3×. It now dedupes on (property, value, important, condition, pseudoElement) per class.

Scraper can run outside DevTools (additive groundwork)

collectStylexDebugData now accepts an optional target — an element or a CSS selector — defaulting to the DevTools-selected element ($0). Passing nothing preserves the existing panel behavior, so this is fully backward compatible. This keeps a single canonical scraper that also works when run outside DevTools (e.g. evaluated by browser automation, where there is no $0).

Feature: "Copy metadata"

New header button + exportMetadata serializer that copies the selected element's StyleX context (resolved declarations grouped by property/condition, data-style-src sources, and overrides) as compact markdown.

Test plan

Tested on Facebook via loading unpacked plugin

image
  • yarn build (clean) emits the CSS and panel.html links the actual file.
  • yarn jest packages/@stylexjs/devtools-extension --watchman=false passes.
  • yarn flow check packages/@stylexjs/devtools-extension → no errors.
  • Loaded unpacked: panel is correctly styled, duplicate rows are gone, and "Copy metadata" copies markdown for the selected element.

- Fix unstyled panel: the StyleX unplugin merges/renames the CSS asset
  (e.g. style.css -> style2.css) and only rewrites JS references, leaving
  the static panel.html <link> pointing at a missing file. The copy-static
  plugin now rewrites the stylesheet href to the actual emitted CSS name.
- Dedupe declarations in collectStylexDebugData so an identical atomic rule
  injected into multiple stylesheets (HMR/StrictMode/multi-bundle) no longer
  renders as duplicate rows.
- Parameterize collectStylexDebugData with an optional `target` (element or
  CSS selector), defaulting to `$0`, so the scraper can run outside DevTools.
- Add a "Copy metadata" button + exportMetadata serializer that copies the
  selected element's StyleX context (resolved declarations, sources, overrides)
  as markdown.
@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
stylex Skipped Skipped Jun 16, 2026 8:49pm

Request Review

@mellyeliu mellyeliu requested a review from nmn as a code owner June 16, 2026 20:39
Copilot AI review requested due to automatic review settings June 16, 2026 20:39
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown

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 updates the StyleX DevTools extension to ensure the panel reliably loads its emitted CSS, reduces duplicate declaration rows during inspection, and adds a new “Copy metadata” capability to export StyleX inspection details as markdown.

Changes:

  • Rewrite copied HTML <link href> to point at the actual emitted CSS filename during the Rollup build.
  • Extend collectStylexDebugData with an optional target selector/element and dedupe identical declaration tuples per class.
  • Add metadata export utilities and a new panel header button to copy markdown to the clipboard.

Reviewed changes

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

Show a summary per file
File Description
packages/@stylexjs/devtools-extension/src/utils/exportMetadata.js Adds a markdown serializer for StyleX debug data (“Copy metadata” output).
packages/@stylexjs/devtools-extension/src/panel/components/CopyMetadataButton.js Adds UI + clipboard-copy logic for exporting metadata from the panel.
packages/@stylexjs/devtools-extension/src/panel/App.jsx Wires the new copy button into the panel header.
packages/@stylexjs/devtools-extension/src/inspected/collectStylexDebugData.js Adds target support and dedupes duplicate declaration rows per class.
packages/@stylexjs/devtools-extension/rollup.config.mjs Updates static HTML copying to rewrite CSS links to the emitted CSS asset name.

Comment on lines +57 to +59
const [label, setLabel] = useState('Copy metadata');
const timeoutRef = useRef<?TimeoutID>(null);

Comment on lines +759 to +765
const dedupKey = [
decl.property,
decl.value,
decl.important ? '!' : '',
decl.condition ?? '',
decl.pseudoElement ?? '',
].join('::');
Comment on lines +36 to +38
export function collectStylexDebugData(
target?: HTMLElement | string | null,
): StylexDebugData {
Comment on lines +706 to +710
// Tracks which (property/value/important/condition/pseudoElement) tuples we have
// already recorded per class, so an identical atomic rule appearing in multiple
// stylesheets (common in dev: HMR re-injection, StrictMode, multiple bundles)
// does not render as duplicate rows.
const seenDeclKeys = new Map<string, Set<string>>();
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

workflow: benchmarks/size

Comparison of minified (terser) and compressed (brotli) size results, measured in bytes. Smaller is better.
yarn workspace v1.22.22
yarn run v1.22.22
$ node ./compare.js /tmp/tmp.FBfjPHza4V /tmp/tmp.lowmikirVv

Results Base Patch Ratio
@stylexjs/stylex/lib/cjs/stylex.js
· compressed 1,535 1,535 1.00
· minified 5,166 5,166 1.00
@stylexjs/stylex/lib/cjs/inject.js
· compressed 1,793 1,793 1.00
· minified 4,915 4,915 1.00
benchmarks/size/.build/bundle.js
· compressed 496,650 496,650 1.00
· minified 4,847,840 4,847,840 1.00
benchmarks/size/.build/stylex.css
· compressed 99,757 99,757 1.00
· minified 748,850 748,850 1.00
Done in 0.09s.
Done in 0.34s.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

workflow: benchmarks/perf

Comparison of performance test results, measured in operations per second. Larger is better.
yarn workspace v1.22.22
yarn run v1.22.22
$ node ./compare.js /tmp/tmp.h2pEnqpDEz /tmp/tmp.1msY2r3GNh

Results Base Patch Ratio
babel-plugin: stylex.create
· basic create 593 587 0.99 -
· complex create 65 67 1.03 +
babel-plugin: stylex.createTheme
· basic themes 463 469 1.01 +
· complex themes 32 32 1.00
Done in 0.09s.
Done in 0.37s.

…nup, tests

- Use JSON.stringify for the per-class dedup key so values containing the
  delimiter (e.g. pseudoElement '::before') can't collide.
- Clear the pending label-reset timeout on CopyMetadataButton unmount.
- Add tests: cross-stylesheet dedup, target by selector, target by element,
  and invalid-selector handling.
@mellyeliu mellyeliu merged commit 14635ba into main Jun 16, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants