Patrickkx
Patrickkx

Reputation: 1870

SSR with styled-components - when app.js loads site missing few styles

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.


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,
}],

Upvotes: 3

Views: 7064

Answers (2)

D V Yogesh
D V Yogesh

Reputation: 3700

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'));

Upvotes: 0

probablyup
probablyup

Reputation: 8144

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.

Upvotes: 3

Related Questions