@@ -8,8 +8,6 @@ import { synchronizeDomContent } from './DomMerging/DomSync';
88
99let enableDomPreservation = true ;
1010let navigationEnhancementCallbacks : NavigationEnhancementCallbacks ;
11- let currentNotFoundRenderAbortController : AbortController | null ;
12- const acceptHeader = 'text/html; blazor-enhanced-nav=on' ;
1311
1412export function attachStreamingRenderingListener ( options : SsrStartOptions | undefined , callbacks : NavigationEnhancementCallbacks ) {
1513 navigationEnhancementCallbacks = callbacks ;
@@ -49,61 +47,10 @@ class BlazorStreamingUpdate extends HTMLElement {
4947 } else {
5048 switch ( node . getAttribute ( 'type' ) ) {
5149 case 'redirection' :
52- // We use 'replace' here because it's closest to the non-progressively-enhanced behavior, and will make the most sense
53- // if the async delay was very short, as the user would not perceive having been on the intermediate page.
54- const destinationUrl = toAbsoluteUri ( node . content . textContent ! ) ;
55- const isFormPost = node . getAttribute ( 'from' ) === 'form-post' ;
56- const isEnhancedNav = node . getAttribute ( 'enhanced' ) === 'true' ;
57- if ( isEnhancedNav && isWithinBaseUriSpace ( destinationUrl ) ) {
58- // At this point the destinationUrl might be an opaque URL so we don't know whether it's internal/external or
59- // whether it's even going to the same URL we're currently on. So we don't know how to update the history.
60- // Defer that until the redirection is resolved by performEnhancedPageLoad.
61- const treatAsRedirectionFromMethod = isFormPost ? 'post' : 'get' ;
62- const fetchOptions = undefined ;
63- performEnhancedPageLoad ( destinationUrl , /* interceptedLink */ false , fetchOptions , treatAsRedirectionFromMethod ) ;
64- } else {
65- if ( isFormPost ) {
66- // The URL is not yet updated. Push a whole new entry so that 'back' goes back to the pre-redirection location.
67- // WARNING: The following check to avoid duplicating history entries won't work if the redirection is to an opaque URL.
68- // We could change the server-side logic to return URLs in plaintext if they match the current request URL already,
69- // but it's arguably easier to understand that history non-duplication only works for enhanced nav, which is also the
70- // case for non-streaming responses.
71- if ( destinationUrl !== location . href ) {
72- location . assign ( destinationUrl ) ;
73- }
74- } else {
75- // The URL was already updated on the original link click. Replace so that 'back' goes to the pre-redirection location.
76- location . replace ( destinationUrl ) ;
77- }
78- }
50+ redirect ( node , false ) ;
7951 break ;
8052 case 'not-found' :
81- const componentId = node . getAttribute ( 'componentId' ) ;
82- if ( ! componentId ) {
83- console . error ( 'Streaming content for not-found response does not have a componentId attribute.' ) ;
84- break ;
85- }
86- wrapDocumentInStreamingMarkers ( componentId ) ;
87- const notFoundUrl = toAbsoluteUri ( node . content . textContent ! ) ;
88-
89- if ( componentId ) {
90- currentNotFoundRenderAbortController ?. abort ( ) ;
91- currentNotFoundRenderAbortController = new AbortController ( ) ;
92- const abortSignal = currentNotFoundRenderAbortController . signal ;
93- fetch ( notFoundUrl , Object . assign ( < RequestInit > {
94- signal : abortSignal ,
95- mode : 'no-cors' ,
96- headers : {
97- 'accept' : acceptHeader ,
98- } ,
99- } , undefined ) )
100- . then ( response => response . text ( ) )
101- . then ( html => {
102- const docFrag = document . createRange ( ) . createContextualFragment ( html ) ;
103- insertStreamingContentIntoDocument ( componentId , docFrag ) ;
104- } )
105- . catch ( error => console . error ( 'Failed to fetch not-found content:' , error ) ) ;
106- }
53+ redirect ( node , true ) ;
10754 break ;
10855 case 'error' :
10956 // This is kind of brutal but matches what happens without progressive enhancement
@@ -116,19 +63,33 @@ class BlazorStreamingUpdate extends HTMLElement {
11663 }
11764}
11865
119- function wrapDocumentInStreamingMarkers ( componentIdAsString : string ) : void {
120- // Add a comment before the <head>
121- const markerStart = document . createComment ( `bl:${ componentIdAsString } ` ) ;
122- const head = document . querySelector ( 'head' ) ;
123- document . documentElement . insertBefore ( markerStart , head ) ;
124-
125- // Add a comment after the <body> or after the <head> if <body> is null
126- const markerEnd = document . createComment ( `/bl:${ componentIdAsString } ` ) ;
127- const body = document . querySelector ( 'body' ) ;
128- if ( body && body . parentNode ) {
129- body . parentNode . insertBefore ( markerEnd , body . nextSibling ) ;
130- } else if ( head && head . parentNode ) {
131- head . parentNode . insertBefore ( markerEnd , head . nextSibling ) ;
66+ function redirect ( node : HTMLTemplateElement , changeUrl : boolean ) : void {
67+ // We use 'replace' here because it's closest to the non-progressively-enhanced behavior, and will make the most sense
68+ // if the async delay was very short, as the user would not perceive having been on the intermediate page.
69+ const destinationUrl = toAbsoluteUri ( node . content . textContent ! ) ;
70+ const isFormPost = node . getAttribute ( 'from' ) === 'form-post' ;
71+ const isEnhancedNav = node . getAttribute ( 'enhanced' ) === 'true' ;
72+ if ( isEnhancedNav && isWithinBaseUriSpace ( destinationUrl ) ) {
73+ // At this point the destinationUrl might be an opaque URL so we don't know whether it's internal/external or
74+ // whether it's even going to the same URL we're currently on. So we don't know how to update the history.
75+ // Defer that until the redirection is resolved by performEnhancedPageLoad.
76+ const treatAsRedirectionFromMethod = isFormPost ? 'post' : 'get' ;
77+ const fetchOptions = undefined ;
78+ performEnhancedPageLoad ( destinationUrl , /* interceptedLink */ false , fetchOptions , treatAsRedirectionFromMethod , changeUrl ) ;
79+ } else {
80+ if ( isFormPost ) {
81+ // The URL is not yet updated. Push a whole new entry so that 'back' goes back to the pre-redirection location.
82+ // WARNING: The following check to avoid duplicating history entries won't work if the redirection is to an opaque URL.
83+ // We could change the server-side logic to return URLs in plaintext if they match the current request URL already,
84+ // but it's arguably easier to understand that history non-duplication only works for enhanced nav, which is also the
85+ // case for non-streaming responses.
86+ if ( destinationUrl !== location . href ) {
87+ location . assign ( destinationUrl ) ;
88+ }
89+ } else {
90+ // The URL was already updated on the original link click. Replace so that 'back' goes to the pre-redirection location.
91+ location . replace ( destinationUrl ) ;
92+ }
13293 }
13394}
13495
0 commit comments