Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Components: moving away from Emotion #66806

Open
3 tasks
ciampo opened this issue Nov 7, 2024 · 1 comment
Open
3 tasks

Components: moving away from Emotion #66806

ciampo opened this issue Nov 7, 2024 · 1 comment
Labels
[Package] Components /packages/components

Comments

@ciampo
Copy link
Contributor

ciampo commented Nov 7, 2024

Related to #61232

Goal

  • Replace Emotion with another technology to author styles
  • Build-time compilation (ie. no runtime compilation)
  • Keep classname obfuscation

Context

The @wordpress/components and the @wordpress/block-editor packages use the Emotion for authoring styles.

Emotion is a CSS-in-JS library that dynamically computes and applies styles at runtime, allowing a developer to change the styles based on JS variables / react props. It also allows for locally scoped files (obfuscating classnames), and colocation of styles and markup.

Unfortunately, Emotion also has a few drawbacks:

  • its runtime increases bundle size and slows down code execution in the browser;
  • it pollutes the developer tools;
  • it can conflict with other dependencies if they don't use the same Emotion version as the main project (specifically with Gutenberg, this happens when loading components in Storybook);
  • their caching/serialization can lead to complicated setups with, for example, rendering components inside an iframe

cc @WordPress/gutenberg-components

@ciampo ciampo added the [Package] Components /packages/components label Nov 7, 2024
@ciampo
Copy link
Contributor Author

ciampo commented Nov 7, 2024

Update:

Folks from @WordPress/gutenberg-components spent some time in the past couple of days testing a few approaches.

Long-term goal

As the long-term solution, we discussed replacing Emotion with CSS modules.

@mirka started experimenting with adding the necessary steps to the build:packages npm script, with initially encouraging results.

Goals:

  • create a working build step, which creates the obfuscated class names mapping and appends the styles to the package's existing CSS bundle (both LTR and RTL)
  • refactor each component from Emotion to CSS modules
    • replaced styled components with the underlying un-styled component and move styles to classname
    • replace dynamic props / variables with other equivalent logic (HTML attributes / CSS variables / different class names)
    • find a way around using "components as selectors"
  • Remove StyleProvider component and its usages across the codebase, useCx hook, rtl utility
  • remove any remaining usage of @emotion/* dependencies (storybook, tests setup, etc)

One thing to consider is whether we should use "SCSS" modules instead so that all styles are authored in SCSS across the whole repository. Using SCSS will also allow us to re-use SCSS variables, without the need for re-creating them in another language (as we currently do with JS variables for CSS-in-JS styles).

Intermediate step

We discussed applying an intermediate step, where we'd keep the CSS-in-JS code as "untouched" and possible, and we'd focus on swapping Emotion with another (zero-runtime) CSS-in-JS. We looked at linaria, StyleX, and vanilla-extract.

  • Linaria and vanilla-extract only offer plugins for known build tools (ie. webpack, rollup, vite..). Unfortunately, this is not very compatible with the custom way Gutenberg packages are built (ie. a node script applying a babel transformation on each individual JS/TS/TSX file — no bundling — and a compilation of any SCSS styles into one bundled CSS file). @ciampo experimented with this part, but didn't get very far: using any build tool brings in additional overhead and new issues, and otherwise using the private APIs of linaria and vanilla-extract is not straightforward
  • StyleX does offer a babel plugin, but it will still require custom code to extract the styles and write them to disk, and to correctly watch file changes;
  • In any case, many Emotion features are not compatible with these libraries — in particular, any "dynamic" variable (or any variable that is imported from another file) may not work as expected, meaning that we'd need to refactor the CSS-in-JS code anyway.

For the above reasons, @ciampo 's initial conclusion is that it may be a better strategy to skip the intermediate step, and instead refactor the Emotion code directly to whatever long-term solution we want to adopt (eg. CSS modules).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Components /packages/components
Projects
None yet
Development

No branches or pull requests

1 participant