Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next.js 13 app directory support #34896

Closed
2 tasks done
Tracked by #1723
MidnightDesign opened this issue Oct 26, 2022 · 30 comments · Fixed by #37962
Closed
2 tasks done
Tracked by #1723

Next.js 13 app directory support #34896

MidnightDesign opened this issue Oct 26, 2022 · 30 comments · Fixed by #37962
Assignees
Labels
core Infrastructure work going on behind the scenes package: system Specific to @mui/system

Comments

@MidnightDesign
Copy link
Contributor

MidnightDesign commented Oct 26, 2022

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Summary 💡

Material UI v5 doesn't support Next.js 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: emotion-js/emotion#2928

Examples 🌈

I've created a minimal (failing) example using create-next-app: https://github.com/MidnightDesign/nextjs13-material-ui

Motivation 🔦

No response

@MidnightDesign MidnightDesign added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Oct 26, 2022
@zannager zannager added the package: system Specific to @mui/system label Oct 26, 2022
@oliviertassinari oliviertassinari added the examples Relating to /examples label Oct 26, 2022
@oliviertassinari

This comment was marked as resolved.

@oliviertassinari oliviertassinari marked this as a duplicate of #34893 Oct 26, 2022
@github-actions github-actions bot added duplicate This issue or pull request already exists and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Oct 26, 2022
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Oct 26, 2022
@oliviertassinari oliviertassinari removed package: system Specific to @mui/system examples Relating to /examples labels Oct 26, 2022
@MidnightDesign

This comment was marked as resolved.

@oliviertassinari oliviertassinari removed the duplicate This issue or pull request already exists label Oct 26, 2022
@oliviertassinari

This comment was marked as resolved.

@oliviertassinari oliviertassinari added examples Relating to /examples external dependency Blocked by external dependency, we can’t do anything about it new feature New feature or request package: system Specific to @mui/system and removed new feature New feature or request external dependency Blocked by external dependency, we can’t do anything about it labels Oct 26, 2022
@oliviertassinari oliviertassinari marked this as not a duplicate of #34893 Oct 26, 2022
@oliviertassinari oliviertassinari added the bug 🐛 Something doesn't work label Oct 26, 2022
@MidnightDesign
Copy link
Contributor Author

@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
Copy link
Member

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

Sure, I plan to work on this on Monday, will review once again all the issues.

@mnajdova
Copy link
Member

mnajdova commented May 8, 2023

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.

@alikleit
Copy link

alikleit commented May 17, 2023

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?

@nitigya-joshi03
Copy link

nitigya-joshi03 commented May 18, 2023

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.

@alaindeurveilher
Copy link

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.

@stephaned-ev
Copy link

stephaned-ev commented May 18, 2023

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?

@nitigya-joshi03
Copy link

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.

@ahmedjaved753
Copy link

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

@alikleit
Copy link

alikleit commented May 22, 2023

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.

@sagrawal-code
Copy link

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

@gijsbotje
Copy link
Contributor

@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

@alikleit
Copy link

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

@sagrawal-code
Copy link

sagrawal-code commented May 26, 2023

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: #34898 (comment). 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

@vinverdy
Copy link

vinverdy commented Jul 1, 2023

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

@sharky98
Copy link

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 RSC2 system, this fix does not allow to benefit of the server-side rendering feature3 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 emotion-js/emotion#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?

Footnotes

  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.

@gijsbotje
Copy link
Contributor

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

@sharky98
Copy link

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

@revskill10
Copy link

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

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

@mj12albert mj12albert assigned mj12albert and unassigned mnajdova Jul 21, 2023
@mj12albert
Copy link
Member

mj12albert commented Jul 21, 2023

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 #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 mj12albert added core Infrastructure work going on behind the scenes and removed bug 🐛 Something doesn't work examples Relating to /examples labels Jul 21, 2023
@mj12albert mj12albert linked a pull request Jul 21, 2023 that will close this issue
1 task
@oliviertassinari oliviertassinari changed the title Next.js 13 compatibility (app directory/server components) Next.js 13 app directory support Jul 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Infrastructure work going on behind the scenes package: system Specific to @mui/system
Projects
None yet
Development

Successfully merging a pull request may close this issue.