Closed lukechu10 closed 1 year ago
Yeah this is a great idea! I think the server side stuff should stay as is, because async is already fully supported there, and then an integration on the client side with async components should be great! Of course, we'd also need to support that when we actually render the components on the server, but that shouldn't be a problem.
As for streaming, this is also definitely something I want to set up. There's already some WS stuff on the client side for hot reloading, so similar code could be reused for this. Then it'd just be a matter of setting this up with all the server integrations.
As for streaming, this is also definitely something I want to set up. There's already some WS stuff on the client side for hot reloading, so similar code could be reused for this. Then it'd just be a matter of setting this up with all the server integration
I believe we're talking about two different kinds of streaming here. What I was thinking of was something like https://dev.to/tigt/the-weirdly-obscure-art-of-streamed-html-4gc2 using HTTP chunked transfer encoding.
The way this would work (and also the way ReactJS works too IIRC) would be once a suspense boundary resolves, a snippet of html and some inline js would be sent over the stream and then sycamore would insert it into the right place.
Here's another post that describes how this works in React: https://github.com/reactwg/react-18/discussions/37
I think we are talking about the same thing, but would this use the same HTTP connection stream?
If so, I reckon WS could be very useful for inbuilt realtime operations (maybe a supplementary library).
Either way I'd like to hold off on streaming until the islands system is done, because I think there'll be a lot of integration there. Async components I'm happy to go ahead with after I've finished removing .perseus/
.
I think we are talking about the same thing, but would this use the same HTTP connection stream? The streaming I was thinking about would only be for the initial page loading. The WS based streaming, from what I understood, seems to be for realtime communication between client and server.
Alright, here are my more formal thoughts on this.
make_rx
is converted to a derive macro (if possible), a derive macro helper #[delay_state]
is defined, which can be used to annotate parts of a template's state that are particularly heavy. These can then be generated as usual on the engine-side, but they will be placed into separate JSON files on the engine-side, while placeholders referencing the URLs of those files will be placed in the actual state sent to the browser. Then, the user matches on an Option
(or perhaps a custom enum
) in their template, so the user receives a fallback state while heavy state is requested by the app shell.#[make_rx]
's successor will have put the function .fetch_delayed()
). There should still be old-style preload directives that don't take the state type, for the rare cases in which the user does not know what they're preloading (which would mean delayed state would have to be fetched in the moment). This should be a distinct edge case, though.This should pretty much cover everything this issue focuses on, and, for that reason, I'm going to appropriate this for v2 of Perseus' state platform, which will have a strong focus on browser-side state and asynchronicity. @lukechu10 does this basically cover everything you're talking about? I'm aware I haven't really addressed proper streaming, though I don't think this would convey any real benefit to Perseus (or any Wasm framework) at this stage, since Wasm is still unchunked (something I intend to deal with in 2023). The main network bottleneck would be getting the runtime necessary to handle streaming to the browser in the first place. Delayed state, however, does provide a very satisfactory solution (for me at least) to the problems of very large state.
There is also an argument that the render config should be fetched with a separate request, although this may require intertwining the render context with the Perseus router in a way that could be very technically complex. Hopefully, it will be fairly straightforward, and this will likely reduce the volume of bytes sent on initial page loads substantially (since the render config, which is basically an object defining all the routes in an app) has to be sent with every initial load right now.
Note that this is conceptually, but not functionally, blocked by #225. Development on this will proceed even before that's fixed, if necessary.
I have made a substantial miscalculation: delayed state is a terrible idea! As it stands, commits relating to this will be reverted and the system will not be deployed to main
, let alone an actual release of Perseus. The system could only ever work with pure build state, since request-time delayed state would have to be written separately for every single request, which is not even remotely scalable. Either delayed state would only work with build state, or I implement a special in-memory store for delayed state. The latter option would massively increase the complexity of Perseus' server-side systems, and the former would increase complexity unnecessarily and add a major opportunity for confusion, while also complicating the amalgamation system greatly.
Unless there is an explicit feature request for a build-state-only version of delayed state, it will not be implemented. If anyone was counting on this feature, please let me know by opening a new issue!
This issue is requesting an enhancement to Perseus. Details of the scope will be available in issue labels. The user described the problem related to this request as follows:
The user described the issue as follows:
Perseus already has
get_build_state
and I think that should stay. However, it would be nice to also have a way to integrate with Suspense and async components.There are quite a few details that would need to be decided upon. The first one would be whether suspense is also awaited on the server side or if it is purely a client side construct. Some information on how this is handled in SolidJS (a similar JS library) is available here: https://github.com/solidjs/solid/tree/main/packages/solid-ssr
Another exciting possibility would be SSR streaming. This page (https://nextjs.org/docs/advanced-features/react-18/streaming) describes how NextJS does it with React.
Lastly, how would this work with the existing
get_build_state
? Should it be recommended to perform data-fetching withget_build_state
or usingSuspense
?I'll be willing to work on this but since the scope of this issue is so large, we'll probably need to do this in multiple steps. I can also give guidance on Sycamore's internals/implementations if needed.
Tribble internal data
dHJpYmJsZS1yZXBvcnRlZCxDLWVuaGFuY2VtZW50LGF1dGhvci13aWxsaW5nLXRvLWltcGw=