SSR classNames issue with React, Express and ChakraUI components

154 Views Asked by At

I have a simple project where I am exposing the built FE project (which has React and ChakraUI) through an express server. Things go well until I import a Box component from chakra. It gets rendered through SSR, but without any styling. From what I understand, the classNames from the client are not in sync with the ones on the server. Is there any way I can fix this?

Error message: Prop className did not match. Server: "null" Client: "css-1xip3bv".

SSR part on the server:

// ssr
const renderFullPage = (html, styles) => {
  return `<!DOCTYPE html>
  <html lang="en">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>What is the HTTP code?</title>
      ${styles}
      <script defer src="./bundle.js"></script>
  </head>
  <body>
      <div id="app">${html}</div>
  </body>
  </html>`;
}

app.use('^/$', (req, res) => {
  const html = renderToString(
    <CacheProvider value={cache}>
      <ChakraBaseProvider theme={theme}>
        <CSSReset />
        <App />
      </ChakraBaseProvider>
    </CacheProvider>,
  )

  const emotionChunks = extractCriticalToChunks(html)
  const emotionCss = constructStyleTagsFromChunks(emotionChunks)

  res.contentType('text/html')
  res.status(200)
  res.send(renderFullPage(html, emotionCss))
})

index.js on the FE side and the App component:

index.js

import * as React from 'react'
import { hydrateRoot, createRoot } from 'react-dom/client'
import { ChakraBaseProvider, CSSReset, extendBaseTheme } from '@chakra-ui/react'
import { CacheProvider } from '@emotion/react'
import App from './App'
import { cache } from './createCache'

const theme = extendBaseTheme({
  colors: {
    red: '#C53030',
  }
})

const container = document.getElementById('app')

hydrateRoot(
  container,
  <CacheProvider value={cache}>
    <ChakraBaseProvider theme={theme}>
      <CSSReset />
      <App />
    </ChakraBaseProvider>
  </CacheProvider>,
)

App.jsx

import React from 'react'
import { Box } from '@chakra-ui/react'
import NumberInput from './components/NumberInput'

const App = () => {
  const isClient = typeof window !== "undefined";
  const Component = isClient ? Box : 'div'

  return (
    <>
      <Component bg="red">
        <h1>What is the HTTP code?</h1>
      </Component>
      <div>"What is the HTTP code?" is a project designed to make people's life easier when dealing
        with HTTP response status codes. The purpose is to create a lightweight, reliable and easy
        to use tool that's accesible to everyone, whether you're a seasoned software developer or a
        beginner just starting out. The HTTP response status codes are described in the internet
        standard RFC 9110.
      </div>
      <NumberInput />
    </>
  )
}

export default App

I tried changing the babel file in a few ways, although I am not sure I'm doing it well, my current babel settings are these:

require('@babel/register')({
  ignore: [/(node_modules)/],
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
  ],
  plugins: [[
    "@emotion",
    {
      "sourceMap": true,
      "autoLabel": "dev-only",
      "labelFormat": "[local]",
      "cssPropOptimization": true,
      "ssr": true
    }
  ]]
})

I am expecting the styling on the server to be in sync with the one on the client. For example if I add a red background to the Box component, it should be red, not white as it shows up right now.

Any help is very much appreciated, Thank you.

0

There are 0 best solutions below