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

Out of Order Streaming #78

Open
dgp1130 opened this issue Jan 9, 2024 · 0 comments
Open

Out of Order Streaming #78

dgp1130 opened this issue Jan 9, 2024 · 0 comments
Labels
feature New feature or request

Comments

@dgp1130
Copy link
Owner

dgp1130 commented Jan 9, 2024

I recently discovered that it is possible to stream HTML out of order (without hacky client-side JS) using declarative shadow DOM: https://techhub.social/@develwithoutacause/111723544374367628

I made a demo which confirms that this is possible and can be automated by transforming input HTML and Promise values into a DSD structure with Promise results deferred to the end of the content, where they can be streamed in any order.

https://github.com/dgp1130/out-of-order-streaming/

I think this is super cool and would be a powerful optimization technique, especially considering that it can be done mostly automatically, if developers author the right structure. Since @rules_prerender uses shadow DOM heavily and implements its own <Template /> Preact component, I think it would potentially be feasible to make this work automatically.

The prototype I did used tagged template literals, so I'm not sure exactly how this would work with VDom. I suspect we do something like:

function MyComponent(): VNode {
  return <div>
    <Template shadowrootmode="open">
      <div>Hello, {lazy(world())}!</div>
    </Template>
  </div>;
}

async function world(): Promise<string> {
  await new Promise<void>((resolve) => {
    setTimeout(() => {
      resolve();
    }, 1_000);
  });

  return 'World';
}

lazy() would just make any suspense stuff easier to work with if possible.

I don't think there's a way to easily correlate the <Template shadowrootmode="open" /> component to the world() Promise, but maybe that's fine. I think we could possibly transform the final VDom for the page (or write a custom renderer) which looks for all lazy values, finds the nearest shadow root ancestor, and transforms them to push the Promise HTML to the end of the document. Definitely need to experiment more to see how this can work.

Needless to say this only really makes sense for true SSR. In SSG, there isn't much value to this kind of streaming. We'll want to explore this once we have a real SSR story.

It might also be worth seeing if it's possible to do all these transformations at compile time. If we can do this statically before request time, then basically the entire document can be streamed immediately without invoking user code at all. Only the slots at the end of the document would need to be filled in via SSR. Not sure how feasible that is, especially if SSR'd HTML would want to take advantage of this trick as well, but it's worth looking into at least.

@dgp1130 dgp1130 added the feature New feature or request label Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant