material-ui
material-ui copied to clipboard
Next.js 13 compatibility (app directory/server components)
Duplicates
- [X] I have searched the existing issues
Latest version
- [X] I have tested the latest version
Summary 💡
MUI doesn't work in Next.js 13 server components (app
directory). Even though the error comes from @emotion\react
and not Material UI itself, I think this should be tracked here as well.
The "primary" error (there might be other problems once the Emotion issue is fixed) is:
TypeError: React.createContext is not a function (sc_server)\node_modules@emotion\react\dist\emotion-element-b63ca7c6.cjs.dev.js (20:47)
Related Emotion issue: https://github.com/emotion-js/emotion/issues/2928
Examples 🌈
I've created a minimal (failing) example using create-next-app
: https://github.com/MidnightDesign/nextjs13-material-ui
Motivation 🔦
No response
Duplicate of #34893
@oliviertassinari The error message in #34893 is very different from the one I mentioned here. Also, this was meant to be kind of an overarching issue, because I think there will be more problems other than these two.
OK, then I'm assigning the same person on this issue than in the one I linked, so there is no duplication of effort.
@mnajdova Since your #34905 seems to be the umbrella issue now, feel free to edit this one to be just about the specific problem with Emotion.
@mnajdova Since your https://github.com/mui/material-ui/issues/34905 seems to be the umbrella issue now, feel free to edit this one to be just about the specific problem with Emotion.
Sure, I plan to work on this on Monday, will review once again all the issues.
Hi guys! How's the progress?
Need an example app with Mui and Next 13 app directory.
Next's App Router is officially stable. Would love to know the progress on Material UI's efforts to support Server Components and Next's App directory.
Next's App Router is officially stable. Would love to know progress on MUI's efforts to support Server Components and Next's App directory.
As a first step, we can update the Material UI's components to use the "use client"
directive. After that, we plan to look into adding an alternative MUI System implementation, that will be compatible with RSC. We plan to add it as an add-on to avoid breaking changes.
As a first step, we can update the Material UI's components to use the "use client" directive
IMHO this can be avoided, to make it explicit that they are client components?
Next's App Router is officially stable. Would love to know progress on MUI's efforts to support Server Components and Next's App directory.
As a first step, we can update the Material UI's components to use the
"use client"
directive. After that, we plan to look into adding an alternative MUI System implementation, that will be compatible with RSC. We plan to add it as an add-on to avoid breaking changes.
I would assume only client components would be marked as such? Marking items such as Grid and Typography as client would not be a good move.
well if all the components use the theme context it's kindof unavoidable
well if all the components use the theme context it's kindof unavoidable
All styled components would need to be marked, as they all depend on Emtion's context.
Any take on this so far?
So for now I would say wrapping our components that include mui components with "use-client"
is the way to go?
Can someone share an example code please where Material UI is being used in the /app directory? I am not able to figure out how to do that since there is no documentation for that.
Can someone share example code please where MUi is being used in app directory. I am not able to figure out how to do that since there are no documentation for that.
Strictly speaking, there is no issue with using MUI components in the app directory, as long as they are used in client components. As explained already before in this thread, you need to ‘use client’; your component.s.
So there is no way to use Material UI in a server side rendered Next component? I guess I'll have to dive into something like Tailwind CSS to achieve something like that?
Can someone share example code please where MUi is being used in app directory. I am not able to figure out how to do that since there are no documentation for that.
Strictly speaking, there is no issue with using MUI components in the app directory, as long as they are used in client components. As explained already before in this thread, you need to ‘use client’; your components.
But I was confused about certain things like how in previous nextjs versions, we added _app.tsx and _document.tsx in the page directory. I wanted to know how to do it know in app directory as most of the syntax has changed and including these files in app directory gives error. Can someone help me by providing code or some link for help. Thanks in advance.
Can someone share example code please where MUi is being used in app directory. I am not able to figure out how to do that since there are no documentation for that.
Strictly speaking, there is no issue with using MUI components in the app directory, as long as they are used in client components. As explained already before in this thread, you need to ‘use client’; your components.
But I was confused about certain things like how in previous nextjs versions, we added _app.tsx and _document.tsx in the page directory. I wanted to know how to do it know in app directory as most of the syntax has changed and including these files in app directory gives error. Can someone help me by providing code or some link for help. Thanks in advance.
Not the right thread to discuss this issue. This is a Next js specific concern and not a MUI one. Would be better if discussed on a Next js forum
Can someone share example code please where MUi is being used in app directory. I am not able to figure out how to do that since there are no documentation for that.
Strictly speaking, there is no issue with using MUI components in the app directory, as long as they are used in client components. As explained already before in this thread, you need to ‘use client’; your component.s.
@alaindeurveilher The issue with running this on the client is that the styles wont be calculated and appended to the page before render, where the app will flicker initially without styles until mui loads it's components.
I hope we get a response on that, if mui is considering this issue for and is planned or has an official workaround to compile the styles on the server.
@ahmedjaved753 this is not a Next.js concern to integrate other libraries into their framework.
@alaindeurveilher The issue with running this on the client is that the styles wont be calculated and appended to the page before render, where the app will flicker initially without styles until mui loads it's components.
With NextJS, there isn't any flicker because of SSR for the client components.
@alikleit client component doesn't mean that everything is done on the client side. It just means that the component is interactive and should send JS to the client. The rendering of the component is always done on the server, the only difference is that server components don't send JS to the client themselves. Though, using client components within a server component will still send the JS used in the client component.
Read the next docs for a better explanation: https://nextjs.org/docs/getting-started/react-essentials#client-components
@gijsbotje @sagrawal-code
I believe that we used to add custom code to extract MUI stylesheets from styled components
, useStyles
and so on... and we write it to the document as a style tag with an id and afterwards removing that tag where the client will render.
I do know client component are as well SSR, but that does not mean these will also compile the things mentioned above 😃 so as the pages from pages directories
.
Plus when my view-source
looks like this:
<head>
<meta charset="utf-8" />
<link
rel="stylesheet"
href="/{appname}/_next/static/css/app/[lng]/layout.css?v=1685004279248"
data-precedence="next_static/css/app/[lng]/layout.css"
/>
<title>{appname}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="/appname/_next/static/chunks/polyfills.js" nomodule=""></script>
</head>
While my inspector looks like this:
<head>
<style data-emotion="css k008qs" data-s="">
.css-k008qs {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
</style>
<style data-emotion="css 1piz1jl" data-s="">
.css-1piz1jl {
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: 100%;
}
</style>
<meta charset="utf-8" />
<link
rel="stylesheet"
href="/{appname}/_next/static/css/app/[lng]/layout.css?v=1685004744442"
data-precedence="next_static/css/app/[lng]/layout.css"
/>
<title>{appname}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="/appname/_next/static/chunks/polyfills.js" nomodule=""></script>
</head>
which I ran with a minimalistic layout (will not show you the flicker / but with a complex one - it will) . Then that tell you something?
Unless, there's a proper official way to compose that 😃
I believe that we used to add custom code to extract MUI stylesheets from styled components, useStyles and so on... and we write it to the document as a style tag with an id and afterwards removing that tag where the client will render.
AFAIK, you would need to do something similar for app directory. See here (and the rest of the thread) for an example: https://github.com/mui/material-ui/issues/34898#issuecomment-1473689035. By following the steps described in the thread, you'll get the styles injected inside head
when the page is rendered on the server and the styles will be visible when you view-source
. @alikleit
when using @urql/exchange-graphcache
it throw hydrationError
and warning
Couldn't find __typename when writing. If you're writing to the cache manually have to pass a
__typename property on each entity in your data
Ok, trying to understand a lot today (brain won't let me sleep until I am satisfied with my understanding... or asking question to understand!). I may use less technical words are vaguely/broadly definition, in a way to create a better mental picture for myself. If you feel that those vague/broad terms are too off the track, don't hesitate to correct me.
With the release of v5.14.0, the MUI ecosystem now works inside Next.js /app
router. Works being defined here as there is no errors and everything is build as expected. This was done with a "quick"[^1] fix of adding "use client"
at the top of all components.
But, as I understand the RSC[^2] system, this fix does not allow to benefit of the server-side rendering feature[^3] of the RSC since the "use client"
will trigger "delegating" everything to the user browser as it was before.
As such, component that should be static in nature in the current MUI/Emotion ecosystem (such as Grid
or Box
) would be passed away as client component nonetheless.
So far so good? I think I am not too far off in my understanding 🤔?
I read many of the issues raised regarding this /app
router in many repositories (including https://github.com/emotion-js/emotion/issues/2928). My current conclusion on the state of the CSS-in-JS librairies and frameworks is that those based on dynamic styling philosophy (such as emotion
) will go extinct on the RSC planet without a paradigm shift; while those based on "zero-runtimes" (I translate in my head as build to static HTML/CSS from the user browser point of view) will flourish on the RSC planet. And I have the feeling that the React planet is pushing hard on the RSC (almost to fear that client component are at risk to be removed someday).
So does that leave us with either having one or the other; or a painfully enormous hybrid version where each component has both static for RSC and dynamics for clients components?
[^1]: Well, quick as in the solution is kinda easy to comprehend after the fact, not quick as it was fast to do 😅!
[^2]: So many acronyms... RSC=React Server Component, that's the right acronym, right?
[^3]: Again, my understanding, if I summarize very broadly, a RSC will be static in nature from a user browser point of view (plain HTML/CSS, with very few JS for the plug&play of the RSC inside the Client Components), so using "use client"
in all component, we will never have this.
@sharky98 I think the most important thing that you seem to misunderstand, is that adding "use client"
doesn't tell react to render it on the client. It only tells react that these components needs additional JavaScript to work, not to render. All components are rendered on the server, but only those with "use client"
will get extra JavaScript to, for example, become interactive.
As MUI uses emotion and has dynamic styles based on props, almost all components require additional JavaScript. But they will be rendered on the server for the initial HTML load.
Therefore, you still have the benefit of RSC. But your bundle could be smaller if you extract CSS at build time, either specifically for a component or for the complete library.
Either way, extracting CSS to static files or style blocks will always be faster than relying on JavaScript to compute styles.
@gijsbotje Thank you for the feedback. This helped me update my mental image of the RSC feature.
@sharky98 I think the most important thing that you seem to misunderstand, is that adding
"use client"
doesn't tell react to render it on the client. It only tells react that these components needs additional JavaScript to work, not to render. All components are rendered on the server, but only those with"use client"
will get extra JavaScript to, for example, become interactive.
If Client Component are also server-rendered, how they manage the "no-hooks", "no-browser-specific-variables", etc. that are in place for RSC? Unless they render only a skeleton-like HTML and CSS without any pre-run of the dynamic stuff (which seems to be what Next.js is doing: Components in the Client Component module graph are primarily rendered on the client, but with Next.js, they can also be pre-rendered on the server and hydrated on the client.
in the Good to know
callout, or what React explain: Client components will still run as part of server-side rendering (SSR) or build-time static site generation (SSG), which act as clients to transform React components’ initial render output to HTML that can be rendered before JavaScript bundles are downloaded.
).
In that case, updating my mental image, I would summarize it as RSC are server-rendered with full HTML and CSS and served as static component to the client to be inserted somewhere in the DOM. For the Client Component, they are server-rendered with the bare skeleton HTML and CSS and served to the client alongside some JavaScript for it to do its magic. If I'm not mistaken, in React world, most extra work that JavaScript would do is change the state, which triggers what they call a render.
As MUI uses emotion and has dynamic styles based on props, almost all components require additional JavaScript. But they will be rendered on the server for the initial HTML load. Therefore, you still have the benefit of RSC. But your bundle could be smaller if you extract CSS at build time, either specifically for a component or for the complete library. Either way, extracting CSS to static files or style blocks will always be faster than relying on JavaScript to compute styles.
So, even though I misunderstood the rendering aspect, with this part of your comment, I think my conclusion is pretty much the same? As long as a library such as MUI is based on CSS-in-JS framework using a dynamic styling philosophy, RSC are impossible; only the benefit of whatever the server is able to do during the first rendering is added (or kept, since it was already like that before the RSC
-era). The way I see it, to allow full-RSC on some components, either emotion will need to change its philosophy (probably not happening), or MUI will need to use some kind of hybrid philosophy.
use client
works with even when you disable JS. The output is still SSR, SEO-able.
But you need to enable JS to useState
,...
Closing this as MUI libraries are compatible as of 5.14.0
with the app directory of Next.js! By compatible we mean that it works as before with the page directory. This means that developers can start their migration from pages to app 🎉.
You can follow https://github.com/mui/material-ui/issues/34905 to see what's coming next to improve Next.js integration.
either emotion will need to change its philosophy (probably not happening), or MUI will need to use some kind of hybrid philosophy
We have started to explore a zero-runtime CSS solution, you can check out the very beginning of this effort here, and keep an eye out for a proper RFC next week!