Storybook: Deduplicate injected package stylesheets#76158
Conversation
Extract shared ref-counted style injection into useSharedStyle hook, used by both WithRTL and WithGlobalCSS decorators.
|
Size Change: 0 B Total Size: 6.87 MB ℹ️ View Unchanged
|
|
Flaky tests detected in 6483564. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/22729403489
|
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
| useSharedStyle( { | ||
| key: 'global:' + context.globals.css, | ||
| cssText: lazyStyles.join( '\n' ), | ||
| } ); |
There was a problem hiding this comment.
Curious: Do we need this key at all. Could this just be ... ?
| useSharedStyle( { | |
| key: 'global:' + context.globals.css, | |
| cssText: lazyStyles.join( '\n' ), | |
| } ); | |
| useSharedStyle( lazyStyles.join( '\n' ) ); |
Granted, these strings could be pretty long, but we're holding them in memory regardless, and I dunno if that would really impact the map lookup performance vs. shorter keys.
Or is there some reason the key needs to be stable independent from the CSS text?
There was a problem hiding this comment.
Granted, these strings could be pretty long, but we're holding them in memory regardless, and I dunno if that would really impact the map lookup performance vs. shorter keys.
It doesn't initially seem that it should have a significant impact:
short key x 300,047,730 ops/sec ±5.03% (79 runs sampled)
long key x 288,352,484 ops/sec ±6.24% (76 runs sampled)
Benchmarking code
import Benchmark from "benchmark";
const suite = new Benchmark.Suite();
const shortKey = "a";
const longKey = "a".repeat(500);
const mapShortKeys = new Map([[shortKey, true]]);
const mapLongKeys = new Map([[longKey, true]]);
suite.add("short key", () => {
mapShortKeys.get(shortKey);
});
suite.add("long key", () => {
mapLongKeys.get(longKey);
});
suite
.run({ async: true })
.on("cycle", (event) => {
console.log(String(event.target));
})
.on("complete", () => {
console.log("Fastest is " + suite.filter("fastest").map("name"));
});|
An error I noticed while testing this, though it also exists in the current version as well: After clicking "Reset selection" in the text direction or global styles dropdown, it errors: https://wordpress.github.io/gutenberg/?path=/docs/components-button--docs&globals=direction:_reset
https://wordpress.github.io/gutenberg/?path=/docs/components-button--docs&globals=css:_reset
Optional if we want to address here, since it exists already. |
Fix in #76205 |


What?
Deduplicates the
<style>elements that Storybook decorators inject into the document head for package stylesheets.Why?
The
WithRTLandWithGlobalCSSdecorators each create a<style>element per story instance. On the Docs tab, where multiple stories render simultaneously (e.g. Primary + all variants), this results in the full package stylesheet being duplicated N times in the<head>.From a practical standpoint, this makes it harder to make temporary style changes in dev tools. In fact I've already made mistakes due to this behavior, thinking I'd disabled a declaration when in reality it just fell through to the duplicate rules.
This was introduced in #74396 (Storybook v10 + Vite migration), which replaced Webpack style-loader's lazy loading (
style.use()/style.unuse()with built-in reference counting) with manual<style>element creation via Vite's?inlineimports.How?
Extracts a shared
useSharedStylehook that ref-counts<style>elements by key. Multiple story instances that resolve to the same key share a single<style>element; it's removed from the DOM only when the last consumer unmounts.Both
WithRTLandWithGlobalCSSnow use this hook instead of directly creating elements.Testing Instructions
npm run storybook:dev).path=/docs/components-button--docs).<style>element for the@wordpress/componentsstylesheet, rather than one per story.Can also verify with: