razzle
razzle copied to clipboard
SSR + suspense + lazy + server components
Is there a roadmap for Razzle integration of React 18 features: SSR + suspense + lazy + server components? Looks like the future of SSR. This is the best starting point for i've found up-to-date info and discussion:
https://github.com/reactwg/react-18/discussions/37
The hot new API looks like renderToPipeableStream....
Thanks!
No roadmap but razzle5 is aiming for this.
While you are waiting for Razzle 5, I'd just say you can try that new hot API now
export const renderApp = (req, res) => {
const context = {};
let didError = false;
const { pipe, abort } = renderToPipeableStream(
<Html assets={assets}>
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
</Html>,
{
onShellError(x) {
didError = true;
console.error(x);
},
onShellReady() {
res.statusCode = didError ? 500 : 200; //handle the error however you'd like to
res.setHeader("Content-type", "text/html");
res.write('<!DOCTYPE html>');
pipe(res);
}
}
);
setTimeout(abort, 60000); //abandon if it takes too long
}
then
function handleErrors(fn) {
return async function (req, res, next) {
try {
return await fn(req, res);
}
catch (x) {
next(x);
}
};
}
and
//const server = express();
server.get('/*', handleErrors(async function (req, res) {
renderApp(req, res);
}));
and create a Html.jsx file like this
export default function Html(props) {
const { assets, children } = props;
const cssLinksFromAssets = (assets, entrypoint) => {
return assets ? assets[entrypoint] ? assets[entrypoint].css ?
assets[entrypoint].css.map(asset =>
<link rel="stylesheet" href={`${asset}`} />
) : '' : '' : ""
};
const jsScriptTagsFromAssets = (assets, entrypoint, ...extra) => {
return assets ? assets[entrypoint] ? assets[entrypoint].js ?
assets[entrypoint].js.map(asset =>
<script src={`${asset} ${extra.join(" ")}`}></script>
) : '' : '' : '';
};
return (
<html>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="icon" href="/img/favicon.png" />
{cssLinksFromAssets(assets, 'client')}
</head> {/*You can also use res.write(`<html><head>...${cssLinksFromAssets(assets, 'client')}</head><body>`) before pipe(res) and after pipe(res) add res.write(`${jsScript...}</body></html>`). This way, you can use Razzle's default jsScriptTagsFromAssets and cssLinksFromAssets, idk if it's a bad practice tho*/}
<body>
<div id="root">{children}</div>
{jsScriptTagsFromAssets(assets, 'client', '', '')}
</body>
</html>
);
};
Just saying that this worked for me
"idk if it's a bad practice tho"
I think this depends on whether you're rendering/hydrating the whole document or only the div id="root" container node. If it's the whole document, then I believe it needs to be all as react components. If it's the container node, you can probably use res.write().
@therealgilles yeah, right, thanks :)