[poc] Support a version of Material UI without CSS in JS#44407
[poc] Support a version of Material UI without CSS in JS#44407mnajdova wants to merge 144 commits into
Conversation
Netlify deploy previewBundle size reportBundle size will be reported once CircleCI build #832201 finishes. |
…/mui-css-layer
…i into feat/mui-css-layer
…/mui-css-layer
…/mui-css-layer
…/mui-css-layer
b13aac2 to
df56225
Compare
At some point I switched to plain CSS, the plain CSS vs CSS modules is a discussion that we should have
Happy with the second proposal is more aggressive. From technical point of view, switching between the two shouldn't be too complicated.
So far for me, AI was the tool :D But it was a bit buggy, I'll admit. One thing that we will need to figure out is documentation, do we want to still show how you can override everything with Emotion & sx? Do we need a Tailwind CSS/Plain CSS demos? This could be huge amount of work, that we should plan on ahead of time. |
40c09c7 to
16e9181
Compare
This PR serves as a proof of concept of how we can build Material UI components using plain CSS, but still allow CSS-in-JS users to use all of the previously available APIs, like
sxprop,styleOverridesetc if they want to. On the other hand, for users that care about performance or want to use plain CSS/Tailwind CSS for customisation, they don't have to pay any penalty of bundle size or performance that comes from using CSS-in-JS.The PR also adds the @mui/tailwind package that hosts plugins and theme overrides for Tailwind to make it easier to test out. We could extract this package and publish it independently.
Finally, the PR also tests how using only a css file, that's build from the theme via a script (build:theme-css), could be used instead of using the theme provider. This css file has all the variables, while each component (such as the Slider) use these variables directly in their respective css files. At the moment, the css file is built in
buildDefaultThemeCss.mtswhere it uses a default theme,generateStyleSheetsandstyleSheetsToStringto stringify the result. We can improve this last part such that consumers could generate the css files from custom themes, even though they could customize the theme in the file as well.Experiments:
While testing, focus on the slider component. Inspect the elements and notice how now the styles are attached to the "utility" classes, e.g.
MuiSlider-rootetc. Emotion and Tailwind CSS overrides still work as expected, leveraging the @layer CSS directive.Example projects:
Initial benchmark:
I did few performance benchmarks and the results are promising. I am comparing the updated
Slidercomponent that is created using plain CSS with the previous one that uses Emotion. On top of it I am adding the same customization (using Emotion) as current users have. There are the results I am getting:Test case 1: Rendering 500 sliders without any customization
Emotion - commit time: 2.8s
Plain CSS - commit time: 0.9s (3.1 x faster)
Test case 2: Rendering 500 sliders using sx prop with one CSS property
Emotion - commit time: 2.8s
Plain CSS - commit time: 1.1s (2.54 x faster)
Test case 3: Rendering 500 sliders using a long sx prop (iOS Slider example)
Emotion - commit time: 3.3s
Plain CSS - 1.8 (1.83 x faster)
Conclusion: In the worst case scenario, the component was 1.8 times faster. The most common use-cases will likely lie somewhere between the Test case 2 and Test case 3, which is still a substantial improvement. For every component that don't need customisation, the gain is already huge (3 times faster). Again, this is a bit of an artificial example, that uses only one component as benchmark but we can already see the size of the impact.
Todos:
[dir='rtl']selectors to styles that are not RTL ready by default, such as the horizontal transforms.'data'ascolorSchemeSelector@custom-variant dark (&:where([data-mui-color-scheme='dark'], [data-mui-color-scheme='dark'] *));to global.css for tailwind mappinguseMountedin the experiments becauseuseColorSchemereturns undefined on the server and an actual value on the client, and switching the value with the Switch will create a hydration mismatch warning.We can use the
theme.generateStyleSheets()for this, however, as the functions generates JS syntax stylesheet, I used this converter to convert it to string (very fast AI generated implementation). We can provide it as a util out of Material UI.theme.generateStyleSheets()createCssVarsProviderto inject the variablesThemeProviderWithVarsis the one supplyingCssVarsInjectorintocreateCssVarsProvider.--mui-transition-duration-shortestand--mui-transition-easing-easeInOut, according to the fallbacks found increateTransitions.jscreateTheme)CssThemeProviderthat aims to replaceThemeProviderwhen Emotion is not used, but it will still import emotion core, viauseThemeWithoutDefault.useThemeWithoutDefaultentirely.