material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

Next.js 13 compatibility (app directory/server components)

Open MidnightDesign opened this issue 1 year ago • 8 comments

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

MidnightDesign avatar Oct 26 '22 11:10 MidnightDesign

Duplicate of #34893

oliviertassinari avatar Oct 26 '22 14:10 oliviertassinari

@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.

MidnightDesign avatar Oct 26 '22 16:10 MidnightDesign

OK, then I'm assigning the same person on this issue than in the one I linked, so there is no duplication of effort.

oliviertassinari avatar Oct 26 '22 17:10 oliviertassinari

@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.

MidnightDesign avatar Oct 27 '22 18:10 MidnightDesign

@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.

mnajdova avatar Oct 28 '22 08:10 mnajdova

Hi guys! How's the progress?

fanisco avatar Feb 08 '23 22:02 fanisco

Need an example app with Mui and Next 13 app directory.

revskill10 avatar Mar 24 '23 05:03 revskill10

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.

mririgoyen avatar May 04 '23 17:05 mririgoyen

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.

mnajdova avatar May 05 '23 07:05 mnajdova

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?

sagrawal-code avatar May 05 '23 09:05 sagrawal-code

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.

mririgoyen avatar May 05 '23 11:05 mririgoyen

well if all the components use the theme context it's kindof unavoidable

rtrembecky avatar May 05 '23 12:05 rtrembecky

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.

mnajdova avatar May 08 '23 09:05 mnajdova

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?

alikleit avatar May 17 '23 08:05 alikleit

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.

nitigya-joshi03 avatar May 18 '23 10:05 nitigya-joshi03

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 avatar May 18 '23 11:05 alaindeurveilher

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?

stephaned-ev avatar May 18 '23 14:05 stephaned-ev

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.

nitigya-joshi03 avatar May 18 '23 15:05 nitigya-joshi03

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

ahmedjaved753 avatar May 21 '23 22:05 ahmedjaved753

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.

alikleit avatar May 22 '23 09:05 alikleit

@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.

sagrawal-code avatar May 23 '23 09:05 sagrawal-code

@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 avatar May 23 '23 09:05 gijsbotje

@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 😃

alikleit avatar May 25 '23 15:05 alikleit

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

sagrawal-code avatar May 26 '23 03:05 sagrawal-code

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

vinverdy avatar Jul 01 '23 09:07 vinverdy

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 avatar Jul 12 '23 08:07 sharky98

@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 avatar Jul 12 '23 11:07 gijsbotje

@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.

sharky98 avatar Jul 14 '23 00:07 sharky98

use client works with even when you disable JS. The output is still SSR, SEO-able.

But you need to enable JS to useState,...

revskill10 avatar Jul 14 '23 07:07 revskill10

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!

mj12albert avatar Jul 21 '23 14:07 mj12albert