skip to Main Content

Description

I have multiple pages on my NextJS project and the react framework I used is Ant Design V5. The problem is only one pages has working styles but Ant or NextJS is not injecting/matching the styles on other pages properly. I tried the official document and the examples from the Ant GitHub repository but neither of them worked for me.

Questions

The questions are:

  1. What is special about that page that styles are working properly?
  2. Why the styles are not functioning on other pages as well?

Links

  1. The link to my repository: https://github.com/kartevonmorgen/kartevonmorgen.ts on branch isolated-ant-bug
  2. The working page: http://localhost:3000/en/m/main
  3. The broken page: http://localhost:3000/en/m/home
  4. The page with broken styles: http://localhost:3000/en
  5. The official Ant document: https://ant.design/docs/react/use-with-next
  6. The Ant examples GitHub repository: https://github.com/ant-design/ant-design-examples/tree/main/examples

Isolated Codes:

pages/_app.tsx

import { FC } from 'react'
import { AppProps } from 'next/app'
import { ConfigProvider } from 'antd'
import '../styles/globals.css'
import 'typeface-rubik/index.css'


const MyApp: FC<AppProps> = ({ Component, pageProps }) => (
       <ConfigProvider
          theme={{
            token: {
              fontFamily: '"Rubik", sans-serif',
            }
          }}
      >
        {/* eslint-disable-next-line react/jsx-props-no-spreading */}
        <Component {...pageProps} />
      </ConfigProvider>
)

export default MyApp

pages/_document.tsx

import Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext,
} from "next/document";
import { StyleProvider, createCache, extractStyle } from "@ant-design/cssinjs";

const MyDocument = () => (
  <Html lang="en">
    <Head />
    <body>
      <Main />
      <NextScript />
    </body>
  </Html>
)

MyDocument.getInitialProps = async (ctx: DocumentContext) => {
  const cache = createCache();
  const originalRenderPage = ctx.renderPage;
  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App) => (props) =>
        (
          <StyleProvider cache={cache}>
            <App {...props} />
          </StyleProvider>
        ),
    });

  const initialProps = await Document.getInitialProps(ctx);
  // 1.1 extract style which had been used
  const style = extractStyle(cache, true);
  return {
    ...initialProps,
    styles: (
      <>
        {initialProps.styles}
        {/* 1.2 inject css */}
        <style dangerouslySetInnerHTML={{ __html: style }}></style>
      </>
    ),
  };
}

export default MyDocument;

pages/home.tsx

import { Button } from 'antd'

const Home = () => (
  <div className="App">
    <Button type="primary">Button</Button>
  </div>
);

export default Home

Dependencies

{
  "dependencies": {
    "@ant-design/colors": "^5.0.1",
    "@ant-design/compatible": "^5.1.1",
    "@ant-design/cssinjs": "^1.13.2",
    "@ant-design/icons": "^4.4.0",
    "@ant-design/pro-layout": "^7.15.3",
    "@fortawesome/fontawesome-free": "^5.15.2",
    "@fortawesome/fontawesome-svg-core": "^1.2.34",
    "@fortawesome/free-brands-svg-icons": "^5.15.2",
    "@fortawesome/free-regular-svg-icons": "^5.15.2",
    "@fortawesome/free-solid-svg-icons": "^5.15.2",
    "@fortawesome/react-fontawesome": "^0.1.14",
    "@fragaria/address-formatter": "^2.4.0",
    "@next/bundle-analyzer": "^10.1.3",
    "@reduxjs/toolkit": "^1.5.0",
    "ahooks": "^3.7.8",
    "antd": "5.x",
    "axios": "^0.21.1",
    "babel-plugin-import": "^1.13.3",
    "color2k": "^2.0.0",
    "cors": "^2.8.5",
    "csv-parse": "^4.16.0",
    "dotenv": "^8.2.0",
    "highlight.js": "^11.2.0",
    "http-status-codes": "^2.1.4",
    "immer": "^8.0.1",
    "isemail": "^3.2.0",
    "leaflet": "^1.7.1",
    "libphonenumber-js": "^1.9.19",
    "lodash": "^4.17.21",
    "moment": "^2.29.1",
    "next": "^12.3.4",
    "next-plugin-antd-less": "^1.0.6",
    "next-translate": "1.0.1",
    "nominatim-browser": "^2.1.0",
    "opening_hours": "^3.6.0",
    "qs": "^6.9.6",
    "rc-select": "^14.6.0-alpha.0",
    "react": "^18.2.0",
    "react-copy-to-clipboard": "^5.0.4",
    "react-datepicker": "^4.12.0",
    "react-dom": "^18.2.0",
    "react-ionicons": "^4.2.0",
    "react-leaflet": "^3.0.5",
    "react-lowlight": "^2.0.0",
    "react-redux": "^7.2.2",
    "react-use": "^17.4.0",
    "react-virtualized": "^9.22.3",
    "redux": "^4.0.5",
    "sqlite3": "^5.0.2",
    "styled-components": "^5.2.3",
    "styled-jsx": "^3.4.4",
    "swr": "^0.4.0",
    "title-case": "^3.0.3",
    "typeface-rubik": "^1.1.13",
    "valid-url": "^1.0.9"
  },
  "devDependencies": {
    "@fortawesome/fontawesome-common-types": "^0.2.34",
    "@types/jest": "^26.0.24",
    "@types/leaflet": "^1.5.19",
    "@types/lodash": "^4.14.168",
    "@types/node": "^14.14.16",
    "@types/qs": "^6.9.5",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.2",
    "@types/react-redux": "^7.1.16",
    "@types/react-virtualized": "^9.21.11",
    "@types/valid-url": "^1.0.3",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0",
    "autoprefixer": "^10.4.4",
    "eslint": "<8.0.0",
    "eslint-config-airbnb": "^19.0.2",
    "eslint-config-airbnb-typescript": "^16.1.0",
    "eslint-config-next": "^13.4.10",
    "file-loader": "^6.2.0",
    "jest": "^27.0.6",
    "moment-locales-webpack-plugin": "^1.2.0",
    "postcss": "^8.4.12",
    "tailwindcss": "^3.0.24",
    "ts-jest": "^27.0.3",
    "tslib": "^2.6.0",
    "typescript": "^4.4.4"
  }
}

Next.js Config

const nextTranslate = require('next-translate')
const MomentLocalesPlugin = require('moment-locales-webpack-plugin')
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})


module.exports = nextTranslate(
  withBundleAnalyzer({
    webpack: (config, _options) => {
      config.resolve.fallback = { fs: false }

      config.plugins.push(
        new MomentLocalesPlugin({
          localesToKeep: [
            'be',
            'de',
            'es',
            'fr',
            'it',
            'nl',
            'pt',
            'ru'
          ],
        }),
      )

      return config
    },

    redirects: async () => ([
      {
        source: '/maps',
        destination: '/m/main',
        permanent: true,
      },
      {
        source: '/m',
        destination: '/m/main',
        permanent: true,
      },
      {
        source: '/t',
        destination: '/t/main',
        permanent: true,
      },
      {
        source: '/tables',
        destination: '/t/main',
        permanent: true,
      },
      {
        source: '/tables/:path*',
        destination: '/t/:path*',
        permanent: true,
      },
      {
        source:'/renn.html/:slug*',
        destination: 'https://v0.kartevonmorgen.org/renn.html#/:slug*',
        permanent: false
      },
      {
        source:'/businesscard.html/:slug*',
        destination: 'https://v0.kartevonmorgen.org/businesscard.html#/:slug*',
        permanent: false
      },
      {
        source:'/map.html/:slug*',
        destination: 'https://v0.kartevonmorgen.org/map.html#/:slug*',
        permanent: false
      },
      {
        source:'/mapAndEntryList.html/:slug*',
        destination: 'https://v0.kartevonmorgen.org/mapAndEntryList.html#/:slug*',
        permanent: false
      }
    ]),

    i18n: {
      locales: [
        'be',
        'de',
        'en',
        'es',
        'fr',
        'it',
        'nl',
        'pt',
        'ru'
      ],

      defaultLocale: 'de',
    },


  }),
)

Screen shots

/home

Antd button with broken styles

2

Answers


  1. I use antd and nextjs too. In my app I use .ts files to handle styles instead of .css. Here’s a little example I’ve made.

    I know this example is not using nextjs, so in your _app file you just need to do as following:

    function _app( {
      Component,
      pageProps
    }: AppProps ): ReactNode {
    
      ....
    
      return (
        <ConfigProvider
          theme={{
            components: {
              Button: {
                colorPrimary: "#f00"
              }
            }
          }}
        >
          <Component { ...pageProps } />
        </ThemeProvider>
      )
    }
    
    
    Login or Signup to reply.
  2. to solve this problem I use the _document.tsx script

    import Document, { Html, Head, Main, NextScript } from 'next/document'
        import { StyleProvider, createCache, extractStyle } from '@ant-design/cssinjs'
        
        type MyDocumentProps = {
          styles: React.ReactNode
        }
        
        export class MyDocument extends Document<MyDocumentProps> {
          render() {
            return (
              <Html lang="en">
                <Head>{this.props.styles}</Head>
                <body>
                  <Main />
                  <NextScript />
                </body>
              </Html>
            )
          }
        }
        
        MyDocument.getInitialProps = async (ctx) => {
          const originalRenderPage = ctx.renderPage
          const cache = createCache()
        
          ctx.renderPage = () =>
            originalRenderPage({
              enhanceApp: (App) =>
                function EnhanceApp(props) {
                  return (
                    <StyleProvider cache={cache}>
                      <App {...props} />
                    </StyleProvider>
                  )
                },
            })
        
          const initialProps = await Document.getInitialProps(ctx)
        
          return {
            ...initialProps,
            styles: (
              <>
                {initialProps.styles}
                <style dangerouslySetInnerHTML={{ __html: extractStyle(cache) }} />
              </>
            ),
          }
        }
        
        export default MyDocument
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search