ant-design: Next.js fails to render style tags when server emits HTML

Reproduction link

Edit on CodeSandbox

Steps to reproduce

  1. Create a new Next.js 13 app with the “app” directory feature:
npx create-next-app@latest --experimental-app
# or
yarn create next-app --experimental-app
# or
pnpm create next-app --experimental-app
  1. Add ant design to the project
  2. Add a few random components in the “app/page.tsx” file. Don’t forget to add “use client” at the top of the file
  3. Run the “dev” script and open the browser at the specified port
  4. Observe how the page loads without styles for a brief second. After a few moments, the styles get downloaded.

I noticed this issue was introduced with @ant-design/cssinjs v1.3.1. Here is a reproduction link where I modified the yarn.lock file to load an older version on cssinjs (v.1.1.0) where everything loads ok.

Here are also some videos to see how it looks like. Pay attention at the reload button to see when I refresh the page:

Before (using a yarn.lock file that requires cssinjss v.1.1.0):

https://user-images.githubusercontent.com/4083652/209926786-2127bca0-6708-44d0-b962-166807bcc718.mov

After (using the latest version of AntDesign which comes with cssinjs v.1.3.1):

https://user-images.githubusercontent.com/4083652/209926824-ecdb3f27-f805-48fa-97c4-72b6e6dfe468.mov

Other mentions of the issue:

What is expected?

The styles to be loaded together with the HTML as before

What is actually happening?

The styles are loaded after the page loads the HTML

Environment Info
antd 5.1.1
React 18.2.0
System MacOS Ventura 13.0.1
Browser Chrome 108

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 25
  • Comments: 62 (9 by maintainers)

Commits related to this issue

Most upvoted comments

i met same problem when using next@13, please solve this bug

There is the solution in the comments, please read carefully.

install version antd@5.0.0 without this error

For what it is worth, this is my production _document.tsx file that is working correctly for https://cocalc.com right now, to workaround this problem: https://github.com/sagemathinc/cocalc/blob/master/src/packages/next/pages/_document.tsx I’m currently still stuck on nextjs v 12.x, so had to use _document.tsx.

Something that caused me a lot of confusion regarding all of this is that I was importing the wrong copy of “@ant-design/cssinjs”. There’s a version of that package that antd uses, but it’s possibly not exposed, so you have to also install it, and you could end up with a slightly different version; then everything you’re doing in _document.tsx will fail, since it’s using the wrong state. This might have been more of an issue for me, since I’m using pnpm, which is very conservative about exposing package versions.

I’m really looking forward to this somehow getting properly fixed. I can see how it will be difficult, since it seems to be simultaneously neither antd’s nor next.js’s “responsibility” to fix. All that said, it’s very nice that antd v5 doesn’t use separate css anymore, since trying to deal with the very large css that resulted via various hacks wasn’t fun either.

For me personally, explicitly exposing the cssinjs that antd is using would help, e.g., instead of

import { createCache, extractStyle, StyleProvider } from "@ant-design/cssinjs";

I would much prefer to be able to do

import { cssinjs } from "antd";

Without that, I have to use hoisting rules to pnpm to ensure I get the same copy of @ant-design/cssinjs as antd is using. Of the “bazillion” packages in my massive webapp, this is the only one that requires any hoisting rules.

I checked the versions, and it looks like the first time this behavior appears is with v.5.0.1

Update: RFC #40985 passed. Will enter the development process.

We have already released @ant-design/static-style-extract@1.0.1, and now we are preparing the template of next.js and related documentation, please look forward to it

Update: RFC #40985 passed. Will enter the development process.

“antd”: “^5.2.0”, “next”: “13.1.6”

same issue, any update?

This issue happens to me on Nextjs 13.2.3 and antd 5.2.3. I’m not using the app dir for nextjs I’m using the pages dir. Anyone happend to fix this issue ?

@MarkLyck Check the solution in the link posted by @mghizzo. It should work on the latest version of Ant Design:

Check my solution vercel/next.js#44125 (comment)

Yeah I saw this, but that solution is for the app directory layouts, which I’m not using. I tried putting it in _document.tsx in getInitialProps but couldn’t get that working. But I don’t think I use any features from 5.1.0 so for me, downgrading to 5.0.0 until this is fixed is an “okay” temporary solution.

Hopefully this gets resolved soon though, I see it’s been open for 2 weeks 😬

This also seems to affect projects NOT using the app directory. I’m only using the normal pages directory and this is happening to me as well.

I spent hours debugging why my NextJS app had a flash of unstyled content with antd styles, until I found this thread. I downgraded to 5.0.0 and the FOUC no longer occurs.

@mvshvets, you forgot to add the following lineimport '../public/antd.min.css'; There’a an alternative way as well:

'use client'

import React, {useState} from 'react';
import {useServerInsertedHTML} from 'next/navigation';

import {
    createCache,
    extractStyle,
    StyleProvider
} from '@ant-design/cssinjs'

const AntdProvider: React.FunctionComponent<React.PropsWithChildren> = ({children}) => {
    const [cache] = useState(() => createCache());

    useServerInsertedHTML(() => {
        return (
            <script dangerouslySetInnerHTML={{
                __html: `</script>${extractStyle(cache)}<script>`
            }}/>
        )
    });

    return <StyleProvider cache={cache}>{children}</StyleProvider>;
}

export default AntdProvider;
import React from 'react';
import {Metadata} from 'next';
import {Inter} from 'next/font/google';

import AntdProvider from 'src/providers/ant';
import './globals.css'

const inter = Inter({
    subsets: ['latin']
});

const metadata: Metadata = {
    title: 'Pergum',
    description: 'Talent scaling as a service',
}

const RootLayout: React.FunctionComponent<React.PropsWithChildren> = ({children}) => (
    <html lang="en">
        <body className={inter.className}>
            <AntdProvider>{children}</AntdProvider>
        </body>
    </html>
);

export {metadata};
export default RootLayout;

Finally got it to work! 👍 I followed the instructions here and used this repo as an example reference.

image

Steps (‘Whole export’):

  1. Install dependencies
npm install ts-node tslib cross-env --save-dev
npm install @ant-design/static-style-extract
  1. Create the following file tsconfig.node.json
{
  "compilerOptions": {
    "strictNullChecks": true,
    "module": "NodeNext",
    "jsx": "react",
    "esModuleInterop": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}
  1. Create the following file scripts/genAntdCss.tsx

If you are using Antd with default theme, then make sure you use the first option. Otherwise, if you are using custom theme, use the second option (see how withTheme is implemented here). Finally, read more here if you are using mixed/multiple themes

// Script to make SSR work with Antd + Next.js 13
// This will generate a full antd.min.css file directly in the specified directory (e.g. ./public)
// Source: https://github.com/ant-design/create-next-app-antd
import fs from 'fs';
import { extractStyle } from '@ant-design/static-style-extract';
import withTheme from '../theme/index';

const outputPath = './public/antd.min.css';

// 1. default theme

// const css = extractStyle();

// 2. With custom theme

const css = extractStyle(withTheme);

fs.writeFileSync(outputPath, css);

console.log(`🎉 Antd CSS generated at ${outputPath}`);
  1. We then need to modify package.json to automatically execute this script genAntdCss.tsx whenever we run/build our app.
// package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "predev": "ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx",
    "prebuild": "cross-env NODE_ENV=production ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx"
  }
}
  1. Finally, make sure we import the generated css within our pages/_app.tsx:
import { StyleProvider } from '@ant-design/cssinjs';
import type { AppProps } from 'next/app';
import '../public/antd.min.css';
import '../styles/globals.css'; // add this line

export default function App({ Component, pageProps }: AppProps) {
  return (
    <StyleProvider hashPriority="high">
      <Component {...pageProps} />
    </StyleProvider>
  );
}

最近会更新一下文档,提供一个模板出来,抱歉让大家体验不好了。

We’ll update doc recently to provide template for this. Sorry for bad experience.

i met same problem when using next@13, please solve this bug

内联样式可以看到有两个相同内容的 <style id="antd"> 样式节点(造成html文件变大一倍), 无法再生产中使用,你们有什么解决办法吗,V14的版本

哈哈哈,刚打算用 next.js 跟 antd 起一个项目,就遇到这个问题, 来 issue 搜搜看,6 小时前都有动态在回复,得了,一个晚上的时间又没了

install version antd@5.0.0 without this error

This is not possible because our project is using the App component which was released in v5.1.0

我将antd的版本下调到了5.0.0,有趣的是的确如他所说。

install version antd@5.0.0 without this error

This is not possible because our project is using the App component which was released in v5.1.0

内联样式可以看到有两个相同内容的 <style id="antd"> 样式节点(造成html文件变大一倍), 无法再生产中使用,你们有什么解决办法吗,V14的版本

@blockmood the main concern is that styles will be compiled on the server at runtime, and the rendering time could take several seconds. I’ve already opened a ticket for this issue, but it was closed.

@Zeng95 I’m faced with Sider issue now. I want to know how you fixed the problem.

Add the following code to Sider @novarca-suzuki

min-height: 100vh

I spent a long time trying to deal with the conflict between nextjs13 and antd5, finally, they can work together. And then, I added tailwindcss and dark theme support. I created a template for this: Next.js13 app dir with Antd 5 & tailwindcss The whole process is painful, and after I finished my work, I found that the size of the document sent by the server was ten times larger than that of the scheme without using css-in-js, lighthouse also prompts the page to lack " HTML DOCTYPE".

On the whole, I decided to give up letting antd5 and nextjs13 work together.

我花了很长时间试图处理nextjs13和antd5之间的冲突,最终,它们可以一起工作。然后,我添加了tailwindcss和深色主题支持。我为此创建了一个模板:Next.js13 app-dir with Antd 5&tailwindcss

整个过程是痛苦的,在我完成工作后,我发现服务器发送的document的大小比不使用css-in-js方案时大了近十倍(8kb - 40kb),lighthouse还提示页面缺少 HTML DOCTYPE。

总的来说,我决定放弃让antd5和nextjs13一起工作。

@IonelLupu @Lrunlin In the early version of antd v5.0, the extraction style is not set, and the style will be generated repeatedly, causing this problem. eg: https://github.com/ant-design/ant-design/issues/38767 https://github.com/ant-design/ant-design/issues/39418

@mghizzo What is parse? I tried implementing your solution (without the parse function) and now I get errors like:

- Expected server HTML to contain a matching <div> in <body>.
- Hydration failed because the initial UI does not match what was rendered on the server.
- An error occurred during hydration. The server HTML was replaced with client content in <#document>.

Also, the page shows the styles as text on the page. Here is a link: https://codesandbox.io/p/sandbox/busy-feather-vh5bii

Not related to Ant Design. Check this issue: https://github.com/vercel/next.js/issues/44125

This is how you should do it inside the main layout. Screenshot 2023-01-03 alle 12 37 37

Note that ConfigProviderLayout is something inside my project so it may just be <>children</> in your case and parse method comes from “html-react-parser”

Then like in the issue mentioned above, nextjs currently has a bug which will ignore useServerInsertedHTML without a head tag somewhere, so make sure to include also that inside your rootlayout. Screenshot 2023-01-03 alle 12 39 42