The css class names definitions are duplicated for some components - in my case it is duplicated (I guess from my debugging) for MuiIconButton
and MuiModal
- check current behavior
The class names should not be duplicated across components.
My button styles:
The class is duplicated.
Styles definition:
It is working in development mode:
My buttons styles:
and found the definitions:
and from modal:
I can try to prepare the environment to reproduce the problem but right now I just wanted to report it here.
I'm trying to release my application with the production environment.
| Tech | Version |
|--------------|---------|
| Material-UI |1.0.0-beta.10 |
| React |15.6.1 |
| browser | any |
| webpack | ^3.3.0 |
I need some hints where may be the problem. I'm not using withStyles
solution anywhere - I use styled components for styles overriding.
I have already seen some issue around this problem. It was always linked to duplicated className generator instances. I can't help more without a reproduction.
I'm closing the issue for now as not actionable. Let me know if you have a reproduction example.
@oliviertassinari I was able to reproduce the problem. Here is the webpack bin - https://www.webpackbin.com/bins/-KuO6ia3h-JDpBOJncZ3
In my case, I have 2 application roots which are mounted independently to 2 different div. Both use the same material-ui ThemeProvider
wrapped with JssProvider
to override insertionPoint
from _jss_.
Based on createGenerateClassName
function, you use counter to have unique class names
export default function createGenerateClassName(): generateClassName {
let ruleCounter = 0;
return (rule: Rule, sheet?: StyleSheet): string => {
ruleCounter += 1;
warning(
ruleCounter < 1e10,
[
'Material-UI: you might have a memory leak.',
'The ruleCounter is not supposed to grow that much.',
].join(''),
);
if (process.env.NODE_ENV === 'production') {
return `c${ruleCounter}`;
}
if (sheet && sheet.options.meta) {
return `${sheet.options.meta}-${rule.key}-${ruleCounter}`;
}
return `${rule.key}-${ruleCounter}`;
};
}
And my screenshot confirms that for some reason the counter is duplicated.
I need help. I don't know what I'm doing wrong right now.
@darkowic You need to share the jss instance between the different react trees. You should be good with such change.
@oliviertassinari I think I'm doing it using my custom ThemeProvider
<JssProvider registry={context.sheetsRegistry} jss={context.jss}>
<MuiThemeProvider
theme={context.theme}
sheetManage={context.sheetsManager}
{...props}
/>
</JssProvider>
I wrap my every react tree with this.
This issue should be opened.
Sure, let's sum up what we know so far. This issue arise as soon as you are using multiple react rendering tree. The jss provider is going to create two class name generators, one for each tree. Hence we end up with class name conflicts.
@kof Should we extend the JssProvider from react-jss
to accept a class name generator?
WORKAROUND for client-side application: You can create your own createGenerateClassName
and move ruleCounter
outside the wrapper function
import warning from 'warning';
// Returns a function which generates unique class names based on counters.
// When new generator function is created, rule counter is reset.
// We need to reset the rule counter for SSR for each request.
//
// It's an improved version of
// https://github.com/cssinjs/jss/blob/4e6a05dd3f7b6572fdd3ab216861d9e446c20331/src/utils/createGenerateClassName.js
//
// Copied from material-ui due to issue https://github.com/callemall/material-ui/issues/8223
// This counter is moved outside from `createGenerateClassName` to solve the issue
let ruleCounter = 0;
export default function createGenerateClassName() {
return (rule, sheet) => {
ruleCounter += 1;
warning(
ruleCounter < 1e10,
[
'Material-UI: you might have a memory leak.',
'The ruleCounter is not supposed to grow that much.'
].join('')
);
if (process.env.NODE_ENV === 'production') {
return `c${ruleCounter}`;
}
if (sheet && sheet.options.meta) {
return `${sheet.options.meta}-${rule.key}-${ruleCounter}`;
}
return `${rule.key}-${ruleCounter}`;
};
}
Nice one, we had such a use case on the server and I was already planing to for a bold hint in the documentation see #5
But now you actually found a good reason to support 2 parallel running providers.
We need to research if there are use cases for a strong need of multiple parallel JssProviders. If there are, we need to think of something to support it.
@kof You have just found a use case for a multiple parallel JssProviders on the client side. And I think the proposed solution is simple to implement :).
move ruleCounter outside the wrapper function
This will mean that on the server, ruleCounter will never get reseted. We can't do that.
On the server side, the JssProviders definitely needs to support concurrent async rendering of a react tree (strong need). But the current implementation makes it already supported :)
@darkowic Proposed a workaround having no access to the underlying stack. We do. We can do better with this extra flexibility: accepting a class name generator instance.
Also request to the same endpoint should always respond with same class names.
@kof Should we extend the JssProvider from react-jss to accept a class name generator?
import {createGenerateClassName} from 'react-jss'
const generateClassName = createGenerateClassName()
<JssProvider generateClassName={generateClassName}>
<App1 />
</JssProvider>
<JssProvider generateClassName={generateClassName}>
<App2 />
</JssProvider>
<JssProvider classNamePrefix="app-1">
<App1 />
</JssProvider>
<JssProvider classNamePrefix="app-2">
<App2 />
</JssProvider>
Pro 1:
Pro 2:
Actually it makes sense to have both props classNamePrefix
and generateClassName
. First for debugging, second for automated uniqueness of classnames.
I've ran into this issue via https://github.com/facebookincubator/create-react-app/issues/3173 (and the linked reduced test case).
In my case, a material UI-dependant component (v1.0.0-beta.11) was included into an app that also uses material-ui (same versions). In development, this works fine, but in production the layout is broken due to conflicting class names.
I'm not sure if this qualifies as "multiple react rendering trees" and moving var ruleCounter = 0;
before createGenerateClassName()
_did not_ workaround the issue, but commenting out the following, _did_ work:
Sorry, I couldn't provide more info at the time I opened #7855.๐
This comment basically covers the issue I faced when running production build.
A workaround for this in the pipeline?
Created a PR which should fix this in react-jss https://github.com/cssinjs/react-jss/pull/155
So let's sum up.
@darkowic's issues root cause is described here: https://github.com/callemall/material-ui/issues/8223#issuecomment-331076580 and will be fixed thanks to @kof's PR: cssinjs/react-jss#155 and a new warning will be added to prevent this situation in the future: #8341.
@tlvince's issue symptoms are the same, but the root cause is different. You are using a single react render tree. It could be linked to a duplicated Material-UI version installed. Check your warnings and if you can figure out exactly what's going on, please open another issue.
@Robophil's issue is too vague to be actionable.
I had the colliding classnames and adding a prefix in createGenerateClassName
options solved the problem.
Used the great, comprehensive doc here
@oliviertassinari thanks for the summary!
In a single react render tree, this issue is most likely caused by different material-ui versions in your build. Make sure to check your dependency tree and check for material-ui versions being used.
yarn list | grep material-ui
My webpack config is as follows
module.exports = {
entry: {
FirstComp: path.join(paths.JS, '/components/FirstComponent/MyFirstComp.js'),
SecondComp: path.join(paths.JS, '/components/SecondComponent/MySecondComp.js'),
},
}
I have these two components and a common component that is built using the splitChunks option.
I wrapped the default exported component in MyFirstComp and MySecondComp using JSSProvider.
How should I be using the JSSProvider around the common component?
@Sewdn I also think it can be caused by different material-ui versions. This className conflict problem was introduced in my app yesterday when I started to migrate to hooks and the useStyles hook created by makeStyles from @material-ui/styles which is at 3.0.0-alpha.1
Also I was using "@material-ui/core" which is at 3.6.0
Suddenly my app classes and the material-ui classes both started with jss1, counting up in parallel. That would mix everything up. My header for example with jss5 was also styled with the jss5 of let's say MuiListItem.
After following this solution https://github.com/mui-org/material-ui/issues/8223#issuecomment-412349569 by @iamhosseindhv the classes of the mui-components got prefixed with a c and the problem was solved.
@christiaanwesterbeek Are you using the installation step correctly? We use dependency injection. install()
call needs to run before all the higher order component imports.
@oliviertassinari I'm afraid I don't know what step you are referring to. Also, I don't know what install()
is part of and where it needs to be called. I'd be glad to learn more about it, but I need to know where it's documented.
@christiaanwesterbeek I'm referring to https://material-ui.com/css-in-js/basics/#migration-for-material-ui-core-users.
@oliviertassinari Seems that install()
should be called in every component's file? I have thought that we just need to call it once in the entry file. Maybe we need a more clear description.
Maybe I'm wrong, install can't resolve conflicts.
To switch from the default style implementation to this newest version, you need to execute the following code before importing any Material-UI's components:
import { install } from '@material-ui/styles';
install();
@oliviertassinari How to install it before importing any Material-UI's components
?
importing is always be handled by babel and tsc statically
@zheeeng ES modules imports are hoisted to the top of the module and resolved synchronously in the order they are defined. We have been facing the same issue with the Material-UI documentation. The solution was to package everything into a bootstrap.js
module and import it first:
https://github.com/mui-org/material-ui/blob/cb30b43e9c6cd49f9b16536a125456f5ea3a85c5/docs/src/modules/components/bootstrap.js#L1-L13
If the problem persists, please, let's move to the discussion to a different issue.
@oliviertassinari I moved the importing order from
// entry index.js
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import CssBaseline from '@material-ui/core/CssBaseline'
import { install } from '@material-ui/styles'
to
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { install } from '@material-ui/styles'
import CssBaseline from '@material-ui/core/CssBaseline'
the code reports error Cannot read property 'text' of undefined
. By inspecting the theme object, it is empty.
If I switch back the importing order, this part works fine.
const useStyles = makeStyles(
(theme: Theme) => ({
root: {
flexShrink: 0,
color: theme.palette.text.secondary,
},
}),
)
Same problem happens when I wrap the whole application with <StylesProvider>
@zheeeng
the code reports error
Cannot read property 'text' of undefined
. By inspecting the theme object, it is empty.
I had the same problem. It was fixed by either upgrading "@material-ui/core" to 3.6.0 or @material-ui/styles which to 3.0.0-alpha.1. I forgot which. Better do both.
However the exact theme that the function passed to makeStyles would receive, was not the theme that I had created with createMuiTheme. Instead it got the default theme. What I ended up doing was to not rely on whatever theme that would get passed. Instead I imported the theme in every file that the styles needed it.
@christiaanwesterbeek I installed @material-ui/[email protected]
and @material-ui/styles/.0.0-alpha.2
and still have this issue.
This seems unrelated to this issue (8223) at hand. But here goes anyway. Just import theme and don't rely on it being passed to the function that you pass to makeStyles
. And you're done.
Can somebody confirm whether the install step is still required with v3.7.0 ( https://github.com/mui-org/material-ui/releases/tag/v3.7.0 )
@christiaanwesterbeek yes, it's required. We will remove the installation step in Material-UI v4.
@oliviertassinari hey, I'm experiencing this issue with latest v3.9.0, and I am not using the @material-ui/styles, I am still using withStyles
from core
I have two questions.
Thanks
I'm experiencing this issue with latest v3.9.0
@w3nda This is too generic, there is a million different reason for this problem to happen.
should I migrate now to mui/styes or wait to v4 release. (large scale app)
We might revert the classname hashing logic. While it greatly improves the performance on the server, it has a significant cost on the client. Maybe we will provide a flag to enable it instead. So no, I think that the best option is to solve the core issue. Did you try this page https://material-ui.com/guides/server-rendering/#troubleshooting?
@oliviertassinari Thanks for the fast response, I really don't know how to debug the problem and the link you mentioned isn't relevant to me because I serve it as a static site..
Tho the comment I referenced helped me, shouldn't it tell the cause of this issue in my case?
@w3nda Static website has the same issue. You need to generate the HTML, so it will use the server-side rendering API. If the index counter leaks between two pages, the class name won't be correct. Well, I think that a slower class name generator is a good tradeoff compared to the pain it is to debug such a problem (& how frequent it is). So, yes, you can upgrade to @material-ui/styles
, it's a simple escape hatch.
I just had a similar problem and it was an old material-ui import that was in one of our libraries. It worked fine in development mode but was broken in production. I'm pretty sure this was working before, I don't know if a warning could be issued in this case, even if it's clearly our fault.
I updated the versions to match them between projects and everything worked again.
Hi, I am using material just for a single input, button and form on my site and I had to use a <JssProvider />
following this comment https://github.com/mui-org/material-ui/issues/8223#issuecomment-331412432
It's annoying to need this jss provider, is there another fix we can do that would not increase the final build size?
@kopax What are you using JssProvider
for?
Hi @oliviertassinari, In production
before visiting another route (we use react-router):
In production
after visiting a route or in development
Something similar here happens with a form (weird box shadows), we need to visit another page to have the proper css, that happens only in production:
Both issues are fixed if we add JssProvider
. (fixed: we have the same css in production
than in development
)
I have no idea. I can't help with the provided information.
Everything is broken too. I observe wrong order jssXX
classes in production and as result the wrong styling. It happens after refreshing the page.
Can't find the reason yet.
@oliviertassinari perhaps those version number used by [email protected] we are using would help you tell us what's going on:
"@material-ui/core": "^1.4.0",
"@material-ui/icons": "^1.0.0",
"material-ui-chip-input": "1.0.0-beta.6 - 1.0.0-beta.8",
Could you make sure that Material-UI is only bundled once? Using two versions at the same time can create the same buggy behavior.
Well. It's possible. We're using react-admin
which has recommended version ~1.5.
I solved the bug on production by adding JssProvider
. Now I can refresh the page normally.
import React from "react";
import { Admin, Resource } from "react-admin";
import JssProvider from "react-jss/lib/JssProvider";
const App = () => (
<JssProvider>
<Admin dataProvider={dataProvider}>
<Resource name="trip" list={RequestsList} className="resourceItem" />
</Admin>
</JssProvider>
);
export default App;
@andrewkslv this is exactly what we are trying to avoid, we'd prefer to use it without JssProvider
because we only use one Input
and Button
component from @material-ui, instead we prefer to use for the rest another ui for react-admin.
@oliviertassinari I've just checked and I did have some dependencies issues. I fixed it but still got the errors with the following npm ls @material-ui/core
:
โโโฌ @bootstrap-styled/[email protected]
โ โโโ @material-ui/[email protected]
โโโ @material-ui/[email protected]
โโโฌ [email protected]
โโโ @material-ui/[email protected]
After doing:
rm -rf node_modules/@bootstrap-styled/ra-ui/node_modules/@material-ui/
rm -rf node_modules/ra-ui-materialui/node_modules/@material-ui/
npm ls @material-ui/core
โโโฌ @bootstrap-styled/[email protected]
โ โโโ UNMET DEPENDENCY @material-ui/[email protected]
โโโ @material-ui/[email protected]
โโโฌ [email protected]
โโโ UNMET DEPENDENCY @material-ui/[email protected]
Then now it does work (no css issue in production). I guess this is not what I want...
Related project @material-ui dependencies:
Any idea what to do?
@kopax It's hard to tell without something I can debug. I'm happy to hear it's working now.
I have noticed you are using styled-components with Material-UI. If you have some time, I would love to chat about the integration on Gitter.
The working solution isn't natural. Which means it involve task that cannot be run with npm. I will not use it, i gave this as a hint.
We'll have the chance on monday, I'll join the mui gitter channel.
Hi @kopax, did you manage to find a solution?
No not yet. Not without the provider. @oliviertassinari I am on gitter.
@andrewkslv Your solution really worked for me. I'm also using react-admin
and AWS Amplify. Anytime I would deploy my react application to a S3 bucket, the style would be all broken, and your solution really saved me.
Same issue here. Why adding JssProvider helps?
I have added a warning in v4 to warn when duplicated style instances are used: #15422.
I don't know. I raised this issue in react-admin
when they were implementing a new version of material ui to the framework but it was ignored.
https://github.com/marmelab/react-admin/pull/3102#issuecomment-484228320
Where i can find the solution about production build - classnames conflicts #8223 ?
Thanks,
@oliviertassinari Facing this issue again, even though i have followed all the instructions. Since it is working for others, i guess i might be missing something basic.
I'm using following versions of the packages.
"@material-ui/core": "^4.6.1",
"@material-ui/icons": "^4.5.1",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-jss": "^10.0.0",
"react-scripts": "3.2.0"
Update: Issue got resolved. Sorry for not going through documentation thoroughly. This part of the documentation solved my issue.
https://material-ui.com/styles/api/#creategenerateclassname-options-class-name-generator
But somehow, the JSSProvider solution which was working for all others, was not working for me. Anyways, thank you :)
Thanks @KannugoPrithvi , this is the good solution ! https://material-ui.com/styles/api/#creategenerateclassname-options-class-name-generator
Most helpful comment
I had the colliding classnames and adding a prefix in
createGenerateClassName
options solved the problem.Used the great, comprehensive doc here