Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce renderToNodeStream #93

Closed
wants to merge 7 commits into from

Conversation

sventschui
Copy link
Member

@sventschui sventschui commented May 11, 2019

This PR aims to introduce renderToNodeStream.

renderToNodeStream is especially useful when used together with Suspense. This will allow SSR to send HTML to the client as soon as possible.

TODO:

  • Ensure compat with ReactDOMServer.renderToNodeStream
  • Add some more tests
  • Wait for the next release of microbundle since the current one does not allow generators
  • Find a solution for backpressure (see comments)

@developit
Copy link
Member

Hmm - it seems like in order to support backpressure, we'd need to render directly into the stream rather than rendering to a String and converting after. Thoughts?

@sventschui
Copy link
Member Author

I'm not 100% familiar with backpressure in node. From what I understand we would need to create a readable stream that pauses rendering until _read is called (again).

I'll definitely look into this when I find some time and if nobody does so before I do :)

[
"@babel/env",
{
"exclude": [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably set the target to the minimum node version here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well renderToNodeStream requires node 10. The other parts of this package work fine with 9 and more importantly in the browser

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a bit concerned about the async generator

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that point. The renderToNodeStream should only be used in node anyways, thus an async generator feels good to me :)

I'd propose to disallow async generators in eslint as bundling regenerator would result in a massive bundle bloat. That will make sure we don't use it in modules targeted to browsers

@developit
Copy link
Member

developit commented May 20, 2019

This is great and the backpressure support is on point.

One question: does the async support here work with the Suspense API? It seems like it's handling the throwing of a Promise, but it would be doing so quite differently than if there was a <Suspense> root in place. Maybe we should hold off on that bit?

README.md Outdated Show resolved Hide resolved
Co-Authored-By: Jason Miller <[email protected]>
@sventschui
Copy link
Member Author

Can you elaborate a bit on the concerns of the "Suspense" behaviour? The current implementation aims to have the same behaviour as if one would use react-ssr-prepass (not falling back to Suspense' fallback but awaiting all thrown promises)

One thing that is currently not too nice is that the rendering is blocked until one promise resolves but I can't come up with a simple solution to that one.

const VOID_ELEMENTS = /^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/;


function PreactReadableStream(vnode, context, opts) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's safe to use a class here. The current node LTS version supports them natively.

Copy link
Member

@marvinhagemeister marvinhagemeister left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to say that the PR is really cool! You made the right call to wait for generator support in microbundle imo.

One thing I'm pondering about is if we should extract the shared code from the sync version and this one. It would be a tradeoff between perf and ease of maintenance for sure. Personally I'd favour the latter because I'm worried that any future bugs will only be fixed in one place and not the other. We need some more opinions on this. What do you all think?

// the context value as `this.context` just for this component.
let cxType = nodeName.contextType;
let provider = cxType && context[cxType.__c];
let cctx = cxType != null ? (provider ? provider.props.value : cxType._defaultValue) : context;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello! Looks like the use of _defaultValue might be a bug (#130); changing it to __ should fix it.

@Doc999tor
Copy link

Doc999tor commented Jan 20, 2020

Hey, guys
Any thoughts will this PR be merged soon?
Can I offer some help?

@ilanbm
Copy link

ilanbm commented Jan 28, 2020

Any progress here?

import stream from 'stream';

// components without names, kept as a hash for later comparison to return consistent UnnamedComponentXX names.
const UNNAMED = [];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: Seems like a memory leak when keeping references to components around in a global variable

@muturgan
Copy link

everybody already wants to use it in production! how long?

@JoviDeCroock
Copy link
Member

Superseded by #296

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants