@@ -113,19 +113,26 @@ export const startRouter = ({ unmount, islands }) => {
113113 }
114114
115115 const page = fetchPage ( url ) ;
116+ const entry = { page, expires : Date . now ( ) + ROUTER_PAGE_LIFETIME } ;
116117
117118 pages . delete ( url ) ;
118- pages . set ( url , { page , expires : Date . now ( ) + ROUTER_PAGE_LIFETIME } ) ;
119+ pages . set ( url , entry ) ;
119120
120- if ( pages . size > ROUTER_MAX_PAGES ) {
121+ // Redirected pages take two entries (below)
122+ while ( pages . size > ROUTER_MAX_PAGES ) {
121123 pages . delete ( pages . keys ( ) . next ( ) . value ) ;
122124 }
123125
124- // A failure is not kept, so the next attempt fetches again
125126 page . then ( result => {
127+ // A failure is not kept, so the next attempt fetches again
126128 if ( ! result && pages . get ( url ) ?. page === page ) {
127129 pages . delete ( url ) ;
128130 }
131+
132+ // Following the redirect (see the handler) then needs no second fetch
133+ if ( result && result . url !== url ) {
134+ pages . set ( result . url , entry ) ;
135+ }
129136 } ) ;
130137
131138 return page ;
@@ -167,12 +174,21 @@ export const startRouter = ({ unmount, islands }) => {
167174 * Swaps in the page the navigation leads to.
168175 */
169176 async handler ( ) {
170- const page = await loadPage ( withoutFragment ( url . href ) ) ;
177+ const href = withoutFragment ( url . href ) ;
178+ const page = await loadPage ( href ) ;
171179
172180 if ( event . signal . aborted ) {
173181 return ;
174182 }
175183
184+ // Hosts with clean URLs redirect `fs.html` to `fs`: follow the redirect
185+ // as a full load would, replacing this navigation's history entry
186+ if ( page && page . url !== href ) {
187+ navigation . navigate ( page . url + url . hash , { history : 'replace' } ) ;
188+
189+ return ;
190+ }
191+
176192 const doc = page && parsePage ( page , assets ) ;
177193
178194 if ( ! doc ) {
0 commit comments