Visual issues of React Material UI after migrating from v4 to v5
We love working with React Material UI. That's why we were very excited when MUI v5 came out on September 16, 2021.
One of our newest projects had just started and we migrated to MUI v5 almost immediately.
The folks from Material UI provided a migration guide that we found very helpful. There's a neat script that you can run against your entire project to ease the migration from MUI4 to MUI5. So we used that. You can find it here.
The project we migrated went to a production server a week after we migrated it and we started seeing a strange CSS behavior.
Some classes were working well in local development, but were clashing with others when deployed. This created strange visual bugs that only appeared on Production.
The issue
In order to test the issue we had to reproduce it in a neutral environment. We've created a super simple demo in github. You can see it 👉 here 👈.
Example of the App working locally as intended:
Example of the same code on production.
The actual issue
One of our colleagues noticed that we import makeStyles
from 2 different places:
import { makeStyles } from '@material-ui/core/styles';
and
import { makeStyles } from '@mui/styles';
THIS WAS the entire reason for the visual bugs!
This happened because we ran the MUI v4 to v5 migration script and after that, we wrote code that imported makeStyles
from the v4 Material API. We hadn't removed the Material v4 dependencies from our package.json
right away, because we wanted to first make sure that the migration went well.
When running the app locally, there was no indication that something went wrong because the old packages were still in the package.json
, and the CSS class names weren't minified (more on that in the debugging section below).
The Fix
Search through your code for all of the imports of makeStyles
that you have. See if any of them are imported from MUI4. Change them to be imported from MUI5 instead. Respectively:
import { makeStyles } from '@mui/styles';
Example PR that applies the changes from the demo project here.
In general - you should remove all MUI v4 dependencies from your project if you have migrated to MUI v5. This doesn't get automatically done by the MUI migration script, and we delayed doing it just enough to get these bugs.
Debugging
As we started debugging the issue, it turned out some of the CSS class names were clashing with other CSS class names in the production build.
Both the classes were called .jss5
(for example), and both those classes were supposed to act on different components. One was supposed to act only on the Navigation component, and the other was supposed to act only on the page Content component (see images above).
Here, you can see two classes clashing because they have the same name: .jss1
These classes initially had the names .makeStyles-someProfileClassName-1
and .makeStyles-someLayoutButtonClassName-1
Why do they clash now?
Initially we thought it could be a bug in the latest version of the bundle-creator that CRA uses to create the production build.
We also thought that the reason we see it happen so inconsistently could be because of the code splitting that happens when the optimized production build is created. We thought that the clashing names were contained in different files, created when the code gets split. And you hit the issue when both the problem files get loaded at the same time by the browser.
All of this turned out to be wrong because the names of the CSS classes didn't seem to be set during the build process. Rather the names were calculated and created during the component mounting or rendering process. So if a component has the class .jss1
in one of the renderings, it could have a completely different name (for the same CSS class and element) in another rendering (for example .jss5
). This seems to depend on the order in which makeStyles
is called during rendering.
In the above example that we gave - two of the components (navigation and page content) were using different ways to import makeStyles
by mistake.
Importing makeStyles
from two different places means that we are using two different versions of it, from two different versions of Material UI. This is causing a clash in the CSS class names since the different versions are renaming the class names in the same pattern at production time. Namely .jss{number}
.
When both of the occurrences of makeStyles
from the different versions of MaterialUI get loaded in the browser on production - you get both the CSS classes renamed in the same way and the CSS styles applied to both items at the same time. A complete Disaster!
There's another thing left to resolve here. Why was the issue inconsistent then? Why were we failing to reproduce it consistently when we open production? Why was it happening only sometimes?
Well, the reason is the same as described above. Since the names that were given runtime are not the same on every rendering - you can get clashes between class names only on specific occasions.
In conclusion
Remove the old versions of Material UI after migrating to v5. That way you will get warnings and errors if you've called the old version API anywhere in your project.
Hope this helps! ✌️