3

I have SSR implemented with styled-components.

When the page loads with SSR, everything looks good. However, when the app.js is loaded and hydrated together with SSR version, page is missing some styles and few elements breaks.

Whats more - when I turn app locally, with npm start or basically just remove my SSR, everything works fine and styles are being applied correctly.

Important: when I enter the page and app.js loads and styles are broken, if I change route - the new route appears with applied styles correctly and the problem is... gone.

  • SSR loads - styles are fine
  • then after few secs app.js loads (hydration process) - styles are broken

running app locally - no problems with styles

running app without SSR - no problems with styles


So in a brief - if I use SSR im missing some styles, the SSR itself returns proper styles, but after hydration with app.js few components are broken.

I bet it's probably an issue with styled-components. The SSR works fine and everything else, except that one component which is missing styles.


Im aware that it's rather uncomplete information about my case, but to show every part which could be responsible for this error, I should publish whole project, however maybe you experienced similar case and you would help me somehow. Thanks.

Edit: My babel-styled-component-plugin config:

['babel-plugin-styled-components', {
    ssr: true,
    displayName: false,
    fileName: false,
    transpileTemplateLiterals: false,
    minify: false,
}],

2 Answers 2

3

Two things...

1) Make sure you're using the babel plugin; without it there's no guarantee the generated class names will be the same between server and client.

2) In your bundling setup, make sure you're using mostly the same babel config for both client and server. If there's a major discrepancy and the files are being transformed in very different ways, that can affect the generated class name output.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. I know it's hard to understand what the heck is going on in my case, however I've seen a similar issue on github github.com/styled-components/styled-components/issues/1860 unfortunately not solved yet. Anyways - thank you for developing this amazing library, respect.
Out of curiosity, are you using a library like react-apollo that has a data-fetching step during SSR? If so, all that stuff needs to be completed before wrapping your final JSX with the collectStyles call from the ServerStyleSheet instance.
@probablyup I am using nextjs, apollo and styled-components and I ran into this exact issue. How do I go about making sure apollo runs first? I am using a withApollo HOC and wrapping my pages in it.
0

i solved in 4 steps

Server.js

app.get('*', handleRender);


function handleRender (req, res) {
  const activeRoute = routes.find((route) => matchPath(req.url, route)) || {};

  const promise = activeRoute.fetchInitialData ?
    activeRoute.fetchInitialData(req.path) :

    Promise.resolve();

promise.then((data) => {
    const context = { data };
    
    const store = configureStore({});
    const sheet = new ServerStyleSheet(); // ==== STEP -1
    


    const preloadedState = store.getState();

    const html = renderToString(
        sheet.collectStyles(    // === STEP --2
            <Provider store={store}>
                <StaticRouter location={req.url} context={context}>
                    <App/>
                </StaticRouter>
            </Provider>

        )
    );
    const styles = sheet.getStyleTags(); /// === STEP 3
   
    res.send(renderFullPage(html, styles, preloadedState));
});



function renderFullPage (html, styles, preloadedState) {
return `
<!DOCTYPE html>
<html>
  <head>
  <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600&display=swap" rel="stylesheet">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>body,html,div,ul,p{margin:0;padding:0;}</style>
    <title>Characters of Rick And Morty Show</title>
    <style>
      ${globalStyles}
    </style>
    ${styles} // === STEP 4
  </head>
  <body>
    <div id="root">${html}</div>
    <script>
      // WARNING: See the following for security issues around embedding JSON in HTML:
      // https://redux.js.org/recipes/server-rendering/#security-considerations
      window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
    /</g,
    '\\u003c'
)}
    </script>
    <script src="client_bundle.js"></script>
  </body>
</html>
`;

}

client

hydrate(<BrowserRouter>
     <Provider store={store}>
       <App/>
    </Provider>
  </BrowserRouter>, document.getElementById('root'));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.