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

[Blazor] Bring back stateful prerendering #15317

Closed
javiercn opened this issue Oct 23, 2019 · 11 comments
Closed

[Blazor] Bring back stateful prerendering #15317

javiercn opened this issue Oct 23, 2019 · 11 comments
Labels
affected-all This issue impacts all the customers area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-server feature-blazor-server-experience Issues that make Blazor server experience different of Web assembly or Desktop feature-prerendering Issues related to prerendering blazor components severity-major This label is used by an internal tool
Milestone

Comments

@javiercn
Copy link
Member

  • We used to have stateful prerendering where we would render the components on the initial circuit, produce static HTML for it, and keep it around until the client reconnected to it.
  • This provided a very nice model as we would avoid having to render the app again when the client connected to it and it would preserve the work generated during prerendering.
  • The main issues we had with this approach are two:
    • We had to keep the app in memory to guarantee that the client could reach it.
    • MVC and Server side blazor were forced to share a contract as server-side blazor needed to be able to replace the rendering capabilities of MVC for rendering interactive components.

Considering the first issue the most important one, we could bring back a modified version of this feature as follows:

  • Stateful prerendering is an enhancement over the existing server-side rendering support.
    • We would serialize the parameters to HTML as we do today in the descriptor.
    • We would include the Circuit ID for the associated circuit.
    • Upon the browser starting up, we would try to re-connect to the existing circuit first.
      • If that worked, the app would resume from there.
      • If that didn't work, we would start the circuit from scratch.
  • The server keeps a limited pool of prerendered circuits around for a very limited (configurable) set of time.
    • The pool is FIFO, if it gets exhausted the oldest prerendered circuit gets cleaned up.
    • If a client tries to reconnect and fails, then it simply starts a new instance with the original serialized parameters.

At this point the feature becomes an enhancement over the current experience, under regular load conditions the feature saves work and bandwidth on the server by avoiding things like requesting data from services multiple times or duplicating the amount of render requests, and under heavy traffic the feature simply falls-back to the current prerender mode.

Some supporting issues associated with this are #15266 #13607 #14977 #13448

@javiercn javiercn added area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one labels Oct 23, 2019
@javiercn javiercn added this to the 5.0.0-preview1 milestone Oct 23, 2019
@Postlagerkarte
Copy link

Postlagerkarte commented Nov 10, 2019

@javiercn : When we get stateful prerendering will this effect the lifecycle effects? Would be great to get rid of the "firstRender" flag. The fact that the component is rendered twice is a source of confusion for many beginners.

@javiercn
Copy link
Member Author

@Postlagerkarte It should in most cases avoid the duplicated calls, but it's not unavoidable when the service is under heavy load, to keep the app available (similar guarantees as with re-connection)

@javiercn
Copy link
Member Author

#16945

@Eirenarch
Copy link

It would be cool if this can be integrated with client side blazor as well. Maybe the serialized state can be used to recreate the client state without executing the lifecycle events again which would be good because if we get the data from a REST service for example the client wouldn't need to call that service again since the server already did.

@leebenson
Copy link

It's not clear to me whether the solution proposed affects just server-side Blazor, or whether it's a pattern - as @Eirenarch appears to be suggesting - that would lend itself to rehydration via client-side WASM too. In any case, it'd be ideal if this also worked for server -> client prerendering scenarios, where a Blazor WebAssembly project is coupled with Blazor Server to allow generating the initial render as 'live' HTML, and then have client-side Blazor take over.

Coming from React, the typical approach to handle the baton-passing from React SSR -> client-side is to serialize the server state in the resulting HTML, so the client can deserialize back to context/GraphQL cache/whatever else. The client can then avoid having to make redundant API calls (some of which could have side-effects, if called multiple times) for data it was already given on the initial dump.

Since there's already the concept of statefulness in Blazor Server (and without knowing much about the internal details, so forgive this crude analysis), it seems to me that 'serializing' to HTML state could avoided in lieu of something like:

  1. Upon compilation, the Blazor WebAssembly project is compiled to static files that are served by Blazor Server.
  2. Blazor Server handles the initial route, and pre-renders to HTML; the output is dumped to the screen, along with the relevant <script> tags to fire up Blazor WebAssembly
  3. Along with the static assets, a Circuit ID (or whatever the correct parlance is for identifying a connection) is provided along with the initial render.
  4. Blazor WebAssembly picks up this ID, and makes a request back to the server to request state; state is serialized to JSON, and returned back to the Blazor Webassembly client. The 'connection' to the server can be closed/GC'd at that point.
  5. State is rehydrated in the client. HTTP requests that have already been taken care of by the initial server prerender are not requested again. As far as the client is concerned, it has everything it needs from that point to 'take over'
  6. Any additional interaction with the page is done client-side, giving it the typical SPA experience.

Again, I'm not familiar enough with the internals to know whether some of this is already baked in or which parts may be outstanding, but this IMO would put Blazor on par with JS frameworks that offer a (still clunky, but useable) methodology for gaining the benefits of SSR + the experience of SPA after the initial dump.

I'd make this a first-class feature and put it front and centre, so developers really don't have to choose between Server or Client anymore -- it marries the best of both.

@javiercn javiercn added affected-all This issue impacts all the customers severity-major This label is used by an internal tool labels Oct 9, 2020 — with ASP.NET Core Issue Ranking
@ghost
Copy link

ghost commented Oct 9, 2020

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@javiercn javiercn added feature-blazor-server feature-blazor-server-experience Issues that make Blazor server experience different of Web assembly or Desktop feature-prerendering Issues related to prerendering blazor components labels Apr 19, 2021
@SteveSandersonMS
Copy link
Member

@javiercn Should we close this, as the functionality is now subsumed into the pause/resume feature?

@javiercn
Copy link
Member Author

javiercn commented Apr 20, 2021

It's something we could do "on top" as an optimization? It's still definitely hard to explain people why their OnInitializeAsync "runs twice", so I think we can still consider bringing this back with a fallback to pausing and resuming when "under heavy load".

The reality is that this works for the majority of the apps for the majority of time, and now we have a reasonable strategy to support "availablity" under load.

@ghost
Copy link

ghost commented Jul 20, 2021

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@Alerinos
Copy link

@mkArtakMSFT I saw that you are planning .net 8, it is worth getting interested in this problem. Also saw a similar thread already planned there.

@mkArtakMSFT
Copy link
Member

We're going to explore other techniques to enable this scenario.

@mkArtakMSFT mkArtakMSFT closed this as not planned Won't fix, can't repro, duplicate, stale Sep 28, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Oct 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affected-all This issue impacts all the customers area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-server feature-blazor-server-experience Issues that make Blazor server experience different of Web assembly or Desktop feature-prerendering Issues related to prerendering blazor components severity-major This label is used by an internal tool
Projects
None yet
Development

No branches or pull requests

7 participants