-
-
Save ryanflorence/b7f1653404b350483909609e435a8a2d to your computer and use it in GitHub Desktop.
| import ReactDOMServer from "react-dom/server"; | |
| import type { EntryContext } from "@remix-run/core"; | |
| import Remix from "@remix-run/react/server"; | |
| import { renderToString } from "react-dom/server"; | |
| import { ServerStyleSheet } from "styled-components"; | |
| import StylesContext from "./stylesContext"; | |
| export default function handleRequest( | |
| request: Request, | |
| responseStatusCode: number, | |
| responseHeaders: Headers, | |
| remixContext: EntryContext | |
| ) { | |
| const sheet = new ServerStyleSheet(); | |
| // first pass to collect styles | |
| renderToString( | |
| sheet.collectStyles( | |
| <StylesContext.Provider value={null}> | |
| <Remix context={remixContext} url={request.url} /> | |
| </StylesContext.Provider> | |
| ) | |
| ); | |
| // get the styles | |
| let styles = sheet.getStyleTags(); | |
| sheet.seal(); | |
| // second time with the styles on context | |
| let markup = ReactDOMServer.renderToString( | |
| <StylesContext.Provider value={styles}> | |
| <Remix context={remixContext} url={request.url} /> | |
| </StylesContext.Provider> | |
| ); | |
| return new Response("<!DOCTYPE html>" + markup, { | |
| status: responseStatusCode, | |
| headers: { | |
| ...Object.fromEntries(responseHeaders), | |
| "Content-Type": "text/html" | |
| } | |
| }); | |
| } |
| import { Meta, Scripts } from "@remix-run/react"; | |
| import { useContext } from "react"; | |
| import StylesContext from "./stylesContext"; | |
| export default function Root() { | |
| // get styles from context | |
| let styles = useContext(StylesContext); | |
| return ( | |
| <html> | |
| <head> | |
| <Meta /> | |
| {styles} | |
| </head> | |
| <body> | |
| <Scripts /> | |
| </body> | |
| </html> | |
| ); | |
| } |
| import { createContext } from "react"; | |
| export default createContext<null | string>(null); |
Same error here
I faced the same issue. As a workaround you can do the following:
-
Set up styled-components as shown in the Remix documentation.
-
Inside your
root.tsxin the<head/>tag instead of{styles}put the following:
{styles !== null && (<style dangerouslySetInnerHTML={{ __html:</style>${styles}<style>}} /> )}
Please note that this is not a safe solution! According to React documentation:
In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.
That is why I do not recommend using it in production. It can significantly speed up development process though (you don't have to restart dev enviroment each time you make a change). I guess we have to wait until the creators of Remix provide us with dedicated solution.
Thanks, @MilanKrupa for sharing the workaround. For the first time, the pages of my app were rendering with proper styles because of SSR I believe but after client-side hydration, the styles were going away.
I was able to fix the issue by avoiding "dangerouslySetInnerHTML" because that is prone to XSS. here us my snippet of code from root. tsx: styles !== null && <style>{styles}</style>}
Thanks to @ryanflorence for sharing the original integration snippet.
why not just inject the style tags at the end of the <head /> like so?
const markupWithStyles = markup.replace(
/<\s*\/\s*head\s*>/gm,
`${styleTags}</head>`
);
return new Response("<!DOCTYPE html>" + markupWithStyles, {
status: responseStatusCode,
headers: responseHeaders,
});edit: nvm this solution still causes the loss of styles upon rehydration
same for me