react-portal-universal
react-portal-universal copied to clipboard
Support third party dom manipulations
@jesstelford I mentioned you here, because I cannot create an issue in your fork.
I saw in https://github.com/jesstelford/react-portal-universal/blob/43e9ba1e8e2ad84d55de6a43562d869c63fabafe/src/server.tsx#L26, that there is only support for renderToStaticMarkup
. This works totally fine with stream when I put this in stream.on('end', () => {})
.
However, I am using styled-components
to load stylesheets within my stream and using this function here https://github.com/styled-components/styled-components/blob/93a00472e3b9bf2974149e9d767e69e56659fbbb/packages/styled-components/src/models/ServerStyleSheet.js#L74.
My guess now is that interleaveWithNodeStream
from styled-components
never reaches the dom created by react-portal-universal
and therefore it will never append the styles to it. I am not really sure if this following would be the solution to this problem.
My current setup:
Note: with this setup the markup is generated, but the styles are not appended. So basically the library works as expected. But not in combination with streams + styled-components
router.use('^/', (_, res) => {
const portals = new ServerPortal();
const sheet = new ServerStyleSheet();
const jsx = sheet.collectStyles((
portals.collectPortals((
<App />
))
));
const stream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx));
stream.pipe(res, { end: false });
stream.on('end', () => {
const markupPortals = portals.appendUniversalPortals(''); // render statically
const plainPortals = markupPortals.replace(/^[\s\S]*<body>/, '');
res.end(plainPortals);
});
});
Possible solution:
router.use('^/', (_, res) => {
const portals = new ServerPortal();
const sheet = new ServerStyleSheet();
const jsx = sheet.collectStyles((
portals.collectPortals((
<App />
))
));
const stream = sheet.interleaveWithNodeStream((
portals.interleaveWithNodeStream(( // <-- only this here
renderToNodeStream(jsx)
))
));
stream.pipe(res, { end: false });
stream.on('end', () => res.end('</body></html>'));
});
A little follow up on this one (and solution). It seems that streams should work perfectly (tried everything with renderToString). The thing is that this does not output the children (which makes total sense, as this should not be printed here).
I figured that there is a way to add third party support. In here we just need to add something in to interpolate (or any better name) with the children
within React.renderToStaticMarkup
like so:
// interpolate has a default: (input) => input
ReactDOMServer.renderToStaticMarkup(interpolate(children))
And in the usage it would look like (now without streams):
portals.appendUniversalPortals('', (children) => sheet.collectStyles(children));