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

Progressively enhanced navigation #48899

Merged
merged 30 commits into from
Jun 20, 2023

Conversation

SteveSandersonMS
Copy link
Member

Implements #48761

This extends blazor.web.js so that when clicking to navigate between pages or using back/forwards, we attempt to perform the navigation via a fetch request and updating the DOM in place.

The main complexities are:

  • Various error cases
  • Integrating with streaming SSR
  • Integrating with interactive components

Intentional limitation for .NET 8

We are not going to support having both "progressively-enhanced nav" and "interactive router" at the same time. As soon as you add any interactive <Router/>, we will automatically disable enhanced nav.

This is because there are two important routing scenarios we need to support:

  • Single-page app (i.e., interactive <Router/>). In this mode, the router takes over all navigation operations and expects to find some content for every URL you visit (and if not, falls back on a full-page load which may render NotFoundContent). It doesn't make sense to navigate to content through enhanced nav because if the router doesn't know about a given URL, it's going to fall back on full-page load anyway, and by default that will then show NotFoundContent.
  • Multi-page app (i.e., not interactive <Router/>). In this mode there's no <Router/> so we do enhanced nav.

... and in neither case does it make sense to have enhanced nav enabled while there's an interactive <Router/>.

In theory you could use both SPA and MPA routing styles in different parts of the same site, but it would be hard to set up.

  • Navigating from MPA to SPA is easy because it just works. When an interactive <Router/> is added via enhanced nav, that router will take over and now you're in a SPA.
  • Navigating from SPA to MPA is much harder because you need to navigate to some URL that the <Router/> doesn't recognize, so it will do a full-page load. Then you need the matched endpoint to render an MPA page that does not have an interactive <Router/> (so you can't use the same root App component if that contains the interactive router).

Temporary limitations

Until #48763 and #48765 are implemented, this does not fully integrate with interactive components. As a short-term stopgap for preview 6:

  • Enhanced nav is enabled by default when the page starts up
  • Each time it updates the page, it attempts to activate any interactive components that may have dynamically been added
  • As soon as it sees any interactive component, it then disables enhanced nav completely.
    • Reason: It's so that, if you navigate again, it will do a full-page reload and then will be able to activate any new interactive components. If we didn't do this, then it would not be able to activate subsequent interactive components because we don't have a way to add new ones to the existing circuit/WebAssembly runtime, since implementing that is Start interactive components that were added dynamically #48763.

The result of this is that in preview 6, things will work, but won't keep using enhanced nav if you have any interactive components and will just fall back on full-page loads (unless you have an interactive router).

@SteveSandersonMS SteveSandersonMS requested a review from a team as a code owner June 19, 2023 16:41
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Jun 19, 2023
@SteveSandersonMS SteveSandersonMS force-pushed the stevesa/progressively-enhanced-navigation branch from 41d8a58 to b06b0a0 Compare June 20, 2023 13:27
@@ -9,7 +9,7 @@ export function synchronizeAttributes(destination: Element, source: Element) {

// Optimize for the common case where all attributes are unchanged and are even still in the same order
const destAttrsLength = destAttrs.length;
if (destAttrsLength === destAttrs.length) {
if (destAttrsLength === sourceAttrs.length) {
Copy link
Member

Choose a reason for hiding this comment

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

Was there a bug here?

Copy link
Member Author

@SteveSandersonMS SteveSandersonMS Jun 20, 2023

Choose a reason for hiding this comment

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

Yes. I could backport the fix and add another test case to the earlier PR, but it didn't seem worthwhile when both of those things are going in on the same day with this PR.

Copy link
Member

Choose a reason for hiding this comment

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

That's ok, as long as we have a test to cover it, that's good enough

synchronizeDomContent(document, parsedHtml);
} else if ((response.status < 200 || response.status >= 300) && !initialContent) {
// For any non-success response that has no content at all, make up our own error UI
document.documentElement.innerHTML = `Error: ${response.status} ${response.statusText}`;
Copy link
Member

Choose a reason for hiding this comment

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

I don't think you'll actually see the redirects here.

AFAIK, fetch automatically follows the redirects.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, great point. I'll add some further test cases for redirections and make sure we're handling it sensibly (updating the history stack too).

Base automatically changed from stevesa/dom-merging to main June 20, 2023 15:27
@SteveSandersonMS SteveSandersonMS force-pushed the stevesa/progressively-enhanced-navigation branch from 96553e9 to 75323b1 Compare June 20, 2023 15:35
@SteveSandersonMS SteveSandersonMS enabled auto-merge (squash) June 20, 2023 16:48
@SteveSandersonMS SteveSandersonMS merged commit 5384526 into main Jun 20, 2023
@SteveSandersonMS SteveSandersonMS deleted the stevesa/progressively-enhanced-navigation branch June 20, 2023 22:34
@ghost ghost added this to the 8.0-preview6 milestone Jun 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants