Closed daniielp closed 2 years ago
@shorcy Can you try the new _document.js
in the our nextjs example? https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_document.js
It is something that we fix internally but how to configure correctly with NextJS.
That fixed the issue. Thanks a lot, @siriwatknp :)
@siriwatknp it doesn't work for me. I just copied everything from example: _app.js, document.js , I runed codemod to convert v4 JSS to MUI v5 styles. But on first app load appears gigantic icons
Getting the same issue. Then I tried setting style={{width: '1em', height: '1em'}}
and it look somewhat ok, but still resizing. I think the styles aren't loading somehow. I'm using static build btw.
Hi @siriwatknp I am experiencing the same issue.
I followed the repo provided by MUI (https://github.com/mui/material-ui/tree/HEAD/examples/nextjs-with-typescript).
The theme is applied in local dev but not when I deploy to production. (https://btdtech.io/)
As you can see from the website, when you first visit it there is no styling applied. If you use the link to navigate to the ABOUT page then you will see it styled. However if you refresh the ABOUT page, the styling disappears again.
This is the link to the repository for your perusal https://github.com/btdtech/company-website.
Look forward to your reply!
Bac
Hi everyone,
I have been digging and it seems that Emotion cache's style component has to style. Do we know why this is? I really would like to get to the bottom of this, otherwise I might have to find another CSS solution.
Cheers,
Bac
I can confirm that our official example does not work. I looking into this.
It seems like the problem comes from this:
// pages/_document.js
const initialProps = await Document.getInitialProps(ctx);
// console.log(initialProps.html) returns empty string
const emotionStyles = extractCriticalToChunks(initialProps.html);
The initialProps.html
returns an empty string which is why emotion cannot create correct styles. When I downgrade react
from latest(v18.0.0) to v17.0.2
, it works. So I think it is something wrong with NextJS + React 18.
~As a workaround, I suggest downgrading react to v17.0.2
for now and I will open an issue on the nextjs repo.~
I can confirm that the issue comes from nextjs latest
. I switch from latest
to canary
and it works. @btdtech @ApayRus @Shahzayb Can you try the canary
version of nextjs?
-"next": "latest",
+"next": "canary",
Change the package json then run yarn
and yarn build
. It worked for me.
Note that the latest nextjs (v12.1.6) (that does not work) was published 28 days ago and ~I could not find the PR that fixed the issue. If anyone knows, feel free to link the issue and the PR.~
I guess this PR https://github.com/vercel/next.js/pull/36792 fixes the issue.
I can confirm that the issue comes from nextjs
latest
. I switch fromlatest
tocanary
and it works. @btdtech @ApayRus @Shahzayb Can you try thecanary
version of nextjs?-"next": "latest", +"next": "canary",
Change the package json then run
yarn
andyarn build
. It worked for me.Note that the latest nextjs (v12.1.6) (that does not work) was published 28 days ago.
Thank you so much @siriwatknp . It solved the issue!
I can understand that there is a bug in nextjs, but why was yarn important in all of this? I tried NPM but didn't work.
I can confirm that the issue comes from nextjs
latest
. I switch fromlatest
tocanary
and it works. @btdtech @ApayRus @Shahzayb Can you try thecanary
version of nextjs?-"next": "latest", +"next": "canary",
Change the package json then run
yarn
andyarn build
. It worked for me. Note that the latest nextjs (v12.1.6) (that does not work) was published 28 days ago.Thank you so much @siriwatknp . It solved the issue!
I can understand that there is a bug in nextjs, but why was yarn important in all of this? I tried NPM but didn't work.
Thanks, I am closing this issue then.
@siriwatknp I downgraded MUI to 4 :-(
@siriwatknp
One way to fix this (even though I am not sure if it's a fix or just a side-effect) is not to use emotionCache
.
NextJS now support SSR with emotion. This is also working out with a simple _document
file, without the need for enhancing and style injections.
next.config: ( flag emotion )
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
compiler: {
emotion: true,
},
}
module.exports = nextConfig
_document: ( no extra enhance code and injections )
import { Html, Head, Main, NextScript } from 'next/document'
import theme from 'theme'
export default function Document() {
return (
<Html lang="en">
<Head>
<meta name="theme-color" content={theme.palette.primary.main} />
...
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
_app: ( no cache provider )
export default function App({ Component, pageProps }: Props) {
const getLayout = Component.getLayout || ((page) => page)
return (
// <CacheProvider value={emotionCache}>
<ThemeProvider theme={theme}>
{getLayout(<Component {...pageProps} />)}
</ThemeProvider>
// </CacheProvider>
)
}
versions:
"next": "^12.1.6",
"@emotion/react": "^11.8.2",
"@emotion/styled": "^11.8.1",
"@mui/material": "^5.5.3",
"react": "^18.1.0",
"react-dom": "^18.1.0",
@Taliss The difference is that the example uses the advanced approach, not the default approach.
I'm still facing this issue. nothing seems to work for me mentioned above.
ReBank this is the website, I can't give the source code since its enterprise application but I can tell you that I'm using Next.js, MUI, styled-components (not @mui/styled-engine-sc, regular mui configuration with just styled-components styled api). As you can see styles are flickering on the first load. I'm using Next.js SWC and have styled-components turned on in next.config.js and using this configuration. Does anyone have this problem and is there any fix to this?
I'm still facing this issue. nothing seems to work for me mentioned above.
ReBank this is the website, I can't give the source code since its enterprise application but I can tell you that I'm using Next.js, MUI, styled-components (not @mui/styled-engine-sc, regular mui configuration with just styled-components styled api). As you can see styles are flickering on the first load. I'm using Next.js SWC and have styled-components turned on in next.config.js and using this configuration. Does anyone have this problem and is there any fix to this?
I fixed it with adopting styled-engine-sc with yarn resolutions and next webpack resolve alias
I can confirm that the issue comes from nextjs
latest
. I switch fromlatest
tocanary
and it works. @btdtech @ApayRus @Shahzayb Can you try thecanary
version of nextjs?-"next": "latest", +"next": "canary",
Change the package json then run
yarn
andyarn build
. It worked for me.Note that the latest nextjs (v12.1.6) (that does not work) was published 28 days ago and ~I could not find the PR that fixed the issue. If anyone knows, feel free to link the issue and the PR.~
I guess this PR vercel/next.js#36792 fixes the issue.
Hi, I upgraded NextJS from v12.0.10 to v12.1.7-canary.39 and I'm still seeing this issue, the style from the theme won't load on the page's first render, anyone can help?
"next": "^12.2.0",
seems to have fixed the issue.
Working version as of today
"next": "^12.2.0",
"@emotion/react": "^11.9.3",
"@emotion/server": "^11.4.0",
"@emotion/styled": "^11.9.3",
"@mui/icons-material": "^5.8.4",
"@mui/lab": "^5.0.0-alpha.88",
"@mui/material": "^5.8.5",
I can confirm that the issue comes from nextjs
latest
. I switch fromlatest
tocanary
and it works. @btdtech @ApayRus @Shahzayb Can you try thecanary
version of nextjs?-"next": "latest", +"next": "canary",
Change the package json then run
yarn
andyarn build
. It worked for me.Note that the latest nextjs (v12.1.6) (that does not work) was published 28 days ago and ~I could not find the PR that fixed the issue. If anyone knows, feel free to link the issue and the PR.~
I guess this PR vercel/next.js#36792 fixes the issue.
Still facing the same problem, style is not load on first load, I also followed the _document.js. What else am i missing ?
"react": "^17.0.2",
"next": "canary",
"@emotion/cache": "latest",
"@emotion/react": "latest",
"@emotion/server": "latest",
"@emotion/styled": "latest",
"@mui/icons-material": "^5.6.2",
"@mui/lab": "^5.0.0-alpha.78",
"@mui/material": "^5.6.2",
"@mui/styles": "^5.6.2",
"@mui/system": "5.9.1",
Yup...
Just wasted some time with this one. In case this is anyone else's issue.
https://developer.chrome.com/blog/new-in-devtools-102/#network-preview
I used to be able to click on the dev tools preview tab, and see a nicely rendered page. At some point I've presumably upgraded Chrome (or its done it itself π€·ββοΈ) and things stopped working.
I probably never noticed at the time; so when I next clicked on the preview tab I got the whole 'plain html' with no CSS applied. (and assumed I'd broken something)
I've just turned JavaScript via dev tools and checked; and everything is properly rendering.
TLDR; things might actually be working / don't trust the chrome preview tab.
Edit: Not 100% sure CSP applies to inline stylesheets; but I can see the styles in the response so π€·ββοΈ
I followed @Taliss 's comment in this thread: https://github.com/mui/material-ui/issues/30410#issuecomment-1148489813
Works like a charm. I'm using all the latest packages.
Is there a benefit to using the default approach that is missing with this configuration? It just seems needlessly complicated.
Adding this to _document.js finally solved the problem `MyDocument.getInitialProps = async (ctx) => { const originalRenderPage = ctx.renderPage; const cache = createEmotionCache(); const { extractCriticalToChunks } = createEmotionServer(cache);
const sheets = new ServerStyleSheets();
ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => function EnhanceApp(props) { return sheets.collect(<App emotionCache={cache} {...props} />); }, });
const initialProps = await Document.getInitialProps(ctx);
const emotionStyles = extractCriticalToChunks(initialProps.html);
const emotionStyleTags = emotionStyles.styles.map((style) => (
<style
data-emotion={${style.key} ${style.ids.join(" ")}
}
key={style.key}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: style.css }}
/>
));
return { ...initialProps, styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()], emotionStyleTags, }; };`
It seems the example repo is now working. I just changed my _app.ts
and _document.ts
and everything seems to work fine both in local dev and in staging env (wth next build
).
I am testing on Brave Browser (which is just a layer on top of Chrome) version 1.43.93 (with Chromium: 105.0.5195.127) and with the following env:
System:
OS: Linux 5.15 Ubuntu 20.04.5 LTS (Focal Fossa)
Binaries:
Node: 18.9.0
npm: 8.19.1
Browsers:
Chrome: 105.0.5195.125
npmPackages:
@emotion/react: 11.10.x => 11.10.4
@emotion/styled: 11.10.x => 11.10.4
@mui/base: 5.0.0-alpha.98
@mui/core-downloads-tracker: 5.10.6
@mui/icons-material: 5.10.6 => 5.10.6
@mui/material: 5.10.6 => 5.10.6
@mui/private-theming: 5.10.6
@mui/styled-engine: 5.10.6
@mui/system: 5.10.6
@mui/types: 7.2.0
@mui/utils: 5.10.6
@types/react: 18.0.20 => 18.0.20
react: 18.2.0 => 18.2.0
react-dom: 18.2.0 => 18.2.0
typescript: 4.8.3 => 4.8.3
"next": "^12.2.0",
seems to have fixed the issue.Working version as of today
"next": "^12.2.0", "@emotion/react": "^11.9.3", "@emotion/server": "^11.4.0", "@emotion/styled": "^11.9.3", "@mui/icons-material": "^5.8.4", "@mui/lab": "^5.0.0-alpha.88", "@mui/material": "^5.8.5",
I did what daveteu posted above and I still see the same issue happening but not as often. I have: "next": "^12.2.0", "@mui/lab": "^5.0.0-alpha.88", "@mui/material": "^5.8.5", "@mui/styles": "^5.4.1", "@emotion/react": "^11.9.3", "@emotion/server": "^11.4.0", "@emotion/styled": "^11.9.3",
Can anyone help please?
Complete the v5 migration with tss-react, it worked for me. https://mui.com/material-ui/migration/migrating-from-jss/#2-use-tss-react https://docs.tss-react.dev/ssr/next.js#mui-and-tss-use-different-caches
Hey I had come across the same issue. I have tried all the things suggested above but nothing has worked. Oh and my issue isnt only for first time, it never works https://myfreecourse-front-v2-r0rfrryqq-hamza172.vercel.app
Using @Mui v5 Next.js 13 with Typescript
my _document file is `import React from 'react'; import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document'; import { ServerStyleSheets } from '@mui/styles';
export default class MyDocument extends Document { static async getInitialProps(ctx: DocumentContext) { const initialProps = await Document.getInitialProps(ctx); return { ...initialProps }; }
render() { return (
);
} }
// getInitialProps
belongs to _document
(instead of _app
),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
// Render app and page and get the context of the page with collected side effects. const sheets = new ServerStyleSheets(); const originalRenderPage = ctx.renderPage;
ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => sheets.collect(<App {...props} />), });
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps, // Styles fragment is rendered after the app and page rendering finish. styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()], }; }; `
my_app file is `import '@/styles/globals.css' import '@/styles/universal.css' import '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; import ScopedCssBaseline from '@mui/material/ScopedCssBaseline'; import type { AppProps } from 'next/app'
export default function App({ Component,pageProps }: AppProps) { return ( <>
<ScopedCssBaseline>
<Component {...pageProps} />
</ScopedCssBaseline>
</>
); }
`
I followed @Taliss 's comment in this thread: https://github.com/mui/material-ui/issues/30410#issuecomment-1148489813
Works like a charm. I'm using all the latest packages.
I had a similar problem but i worked around it probably with not the best solution. In my case i was making a project using react and django, this project had a google verification to login and after this it load the home page. In the first load only the buttons itens from material ui package were without the styled, but after you refresh the page the style works again. So i created a context to use a variable that apoint this first load and automatically refresh the page. Like i said, this is not the best way but worked for me. I hope someone with it.
"next": "^13.5.2",
"react": "^18.2.0",
"@material-ui/core": "^4.12.4",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.45",
"@material-ui/styles": "^4.11.5",
I have the above configuration work fine but get this issue after updating with the latest version 13.5.2,
@hamza172 I tried your solution but now work in above version
Thanks in advance if anyone can help with this
so what is the right solution now in 2024?
so what is the right solution now in 2024?
@siriwatknp I think it's an important issue. and now after more than 2 years, even with the new versions of Next js, MUI and Emotion, the problem still exists. can you look around please?
I can confirm that not using CacheProvider
, this problem is fixed. But as my app is RTL so I HAVE to use it.
here's _app.js
file:
import * as React from "react";
import Head from "next/head";
import { ThemeProvider } from "@mui/material/styles";
import rtlPlugin from "stylis-plugin-rtl";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";
import { prefixer } from "stylis";
import theme from "../src/theme";
// Create rtl cache
const cacheRtl = createCache({
key: "muirtl",
stylisPlugins: [prefixer, rtlPlugin],
});
function MyApp({ Component, pageProps }) {
return (
<CacheProvider value={cacheRtl}>
<ThemeProvider theme={theme}>
<Head>
// header tags here
</Head>
<Component {...pageProps} />
</ThemeProvider>
</CacheProvider>
);
}
export default MyApp;
commenting <CacheProvider value={cacheRtl}></CacheProvider>
out fixes problem, but makes the app look crushed as it changes to LTR.
https://github.com/mui/material-ui/issues/30410#issuecomment-2037024412 @famdude I have the same issue. Have you come up with a solution?
My solution used suppressHydrationWarning and solved other details.
It works this way:
Ps: Im using Next.js v14 and Material UI v5.16
(simplified code)
Root Layout:
import { CustomThemeProvider } from "@/context/CustomThemeContext";
import React from "react";
import "./globals.css";
// trick to avoid SSR mismatch due to html inline colorMode script
const mockSSRColorMode = () => "light";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html
lang="en"
style={{ colorScheme: mockSSRColorMode() }}
suppressHydrationWarning
>
<head>
{/* Inline script to set color scheme on the first load (to avoid wrong color loading screen) */}
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
const storedColorMode = localStorage.getItem('colorMode');
const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const colorMode = storedColorMode || (prefersDarkMode ? 'dark' : 'light');
document.documentElement.style.colorScheme = colorMode;
})();
`,
}}
/>
</head>
<body>
<CustomThemeProvider>{children}</CustomThemeProvider>
</body>
</html>
);
}
CustomThemeContext:
"use client";
import Loading from "@/app/loading";
import { PaletteMode, useMediaQuery } from "@mui/material";
import {
Theme,
ThemeProvider
} from "@mui/material/styles";
import React, {
createContext,
ReactNode,
useContext,
useEffect,
useMemo,
useState,
} from "react";
interface ThemeContextType {
colorMode: PaletteMode;
toggleColorMode: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
interface CustomThemeProviderProps {
children: ReactNode;
}
export const CustomThemeProvider: React.FC<CustomThemeProviderProps> = ({
children,
}) => {
const [colorMode, setColorMode] = useState<PaletteMode>("light");
const [loading, setLoading] = useState(true);
const sysPreferDark = useMediaQuery("(prefers-color-scheme: dark)", {
noSsr: true,
});
// This prop determines native elements theme
const setColorSchemeOnHtml = (newMode: PaletteMode) =>
document.documentElement.style.setProperty("color-scheme", newMode);
// First-load color-mode routine: use stored OR system-preference OR fallback to 'light'
// Set it on state+themecontext AND on <html>'s color-scheme style prop
useEffect(() => {
const storedColorMode = localStorage.getItem("colorMode") as PaletteMode;
const newMode = storedColorMode || (sysPreferDark ? "dark" : "light");
setColorMode(newMode);
setColorSchemeOnHtml(newMode);
setLoading(false);
}, [sysPreferDark]);
const theme: Theme = useMemo(() => {
// ... mui createStyles()
}, [colorMode]);
// User-triggered color-mode change: set preference on storage and html
const toggleColorMode = () => {
setColorMode((prevMode) => {
const newMode = prevMode === "light" ? "dark" : "light";
localStorage.setItem("colorMode", newMode);
setColorSchemeOnHtml(newMode);
return newMode;
});
};
// on first-load the loading screen is immediatelly displayed
// until the theme is loaded with the uptodate color-mode
if (loading) {
return <Loading />;
}
return (
<ThemeContext.Provider value={{ colorMode, toggleColorMode }}>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</ThemeContext.Provider>
);
};
export const useCustomThemeContext = (): ThemeContextType => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useCustomTheme must be used within a CustomThemeProvider");
}
return context;
};
And no color-scheme related styles on any CSS file.
still happening on Next 14.0.4 , this problem was marked as solved in https://github.com/vercel/next.js/issues/15642 but it is still persisting
Duplicates
Latest version
Current behavior π―
When using SX prop I seem to be getting an issue when deploying the application where a lot of the styles are loaded after the dom has rendered. Even though I use the emotion cache in my _documents.tsx, and create and use the theme in _app.tsx.
Expected behavior π€
What should is that when rendering the page the first time all the style changes should already be there. but takes a small bit of time before it does. https://imgur.com/a/ZujFrXd
Steps to reproduce πΉ
The issue is now only visible on the live site (Hosted with vercel). https://daniiel.dev/
But for you want want to take a look or maybe have an idea what could cause it.
You can have a look at the repo and play around yourself by using the codesandbox bellow codesandbox: https://codesandbox.io/s/hopeful-bush-5jbz8
Context π¦
What I'm trying to accomplish is for my production build to look like my local development on initial load.
I think the issue lays in either the _documents.tsx or _app.tsx.
I have attached a link to the 2 images for how it looks in local development and production. https://imgur.com/a/ZujFrXd
Your environment π
Used both Firefox Developer Edition & Google Chrome (Version: 96.0.4664.110) for testing.
System:
OS: Windows 10 10.0.19044
Binaries:
Node: 16.13.1 - C:\Program Files\nodejs\node.EXE Yarn: Not Found npm: 8.1.2 - C:\Program Files\nodejs\npm.CMD Browsers: Chrome: Not Found Edge: Spartan (44.19041.1266.0), Chromium (96.0.1054.62) npmPackages: @emotion/react: ^11.5.0 => 11.5.0 @emotion/styled: ^11.3.0 => 11.3.0 @mui/core: 5.0.0-alpha.53 @mui/lab: ^5.0.0-alpha.53 => 5.0.0-alpha.53 @mui/material: ^5.0.6 => 5.0.6 @mui/private-theming: 5.0.1 @mui/styled-engine: 5.0.2 @mui/system: 5.0.6 @mui/types: 7.0.0 @mui/utils: 5.0.1 @types/react: ^17.0.34 => 17.0.34 react: ^17.0.2 => 17.0.2 react-dom: ^17.0.2 => 17.0.2 typescript: ^4.3.5 => 4.3.5
--- tsconfig.json --- { "compilerOptions": { "lib": [ "es6", "dom" ], "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, "target": "es5", "allowJs": true, "skipLibCheck": true, "strict": false, "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve" }, "include": [ "next-env.d.ts", "*/.ts", "*/.tsx", "src/components" ], "exclude": [ "node_modules" ] }