preact-render-to-string
preact-render-to-string copied to clipboard
Styled-Components Rendering Incorrectly
Hullo,
First of all I'd like to thank you for your work. I am quite enjoying using your library.
On to my issue:
I have a relatively bare-bones app and I was playing around with your library to generate a static page. However, render to string is refusing to cooperate with styled-components.
The page is quite simple, and can be summarized as:
const Bad = styled.p`
color: red;
`;
export const App = () => (
<>
<Bad>Will Produce bad results</Bad>
<div>this one is ok</div>
</>
)
I use viteJS to first convert the typescript + preact shenanigans into plain old JS; followed by your renderToString to replace the html in the necessary place through a simple script;
await vite.build({
build: {
ssr: true,
rollupOptions: { input: toAbsolute("./src/renderToHtml.tsx") },
outDir: toAbsolute("./dist/ssr_crap"),
// Make things nice and readable while I have a bug...
minify: false,
},
});
const { render } = require("./dist/ssr_crap/renderToHtml.js");
const appHtml = render();
const template = fs.readFileSync(toAbsolute("dist/index.html"), "utf-8");
const html = template.replace(`<!--app-html-->`, appHtml);
const filePath = "dist/index.html";
fs.writeFileSync(toAbsolute(filePath), html);
This results in an index.html that features the styled component rendered not as an html element with a class, but instead as: <.sc-bdvvtL>Hello Vite + Preact!</.sc-bdvvtL>
Furthermore: Attempting to use styled-component's CreateGlobalStyle simply crashes my poor script.
Why I believe the issue is in this specific library
Running ViteJs's normal build results in a working page. To my eye, this means that all of the react aliasing is correctly sorted out.
Stuff I tried but didn't work
Previous issues mentioned how I needed to go back to version 3.X of styled-components; but I found a changelog that mentioned that this was no longer the case.
I also tried to follow styled components SSR guide and apply a similar replace trick as I did with the HTML; but it just resulted in more inscrutible errors.
Reproducible example:
Go here and then run:
$ bash docker_functions.sh # See that the dev environment works
$ bash buggy_styled.sh # See that ssr doesn't :(
Thanks for your time, any help would be appreciated ☺️
Solved by forcefully patching React into my SSR script like so:
// Monkey Patch React
// This is necessary due to a bug in styled-components :(
// See: https://preactjs.com/guide/v8/switching-to-preact/#aliasing-manually
const React = require('react')
const ReactDOM = require('react-dom')
const Preact = require('preact/compat')
const Module = module.constructor
Module._cache[require.resolve('react')].exports = Preact
Module._cache[require.resolve('react-dom')].exports = Preact
Inspired by this guide on the preact docs.
This looks quite fragile to me; and I'm wondering if there's not a better alternative. Although I can close this issue if the maintainers believe it's not their concern
You might want to try the following approach:
yarn add react@npm:@preact/compat react-dom@npm:@preact/compat
As mentioned, this is in all likelihood due to Vite not applying aliases for SSR builds, instead, keeping the modules external.
Adding the alias package (@preact/compat) as suggested would fix this.
Closing, as it's not really an issue with preact-render-to-string and our docs cover this situation