@@ -90,6 +90,7 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
9090 map : mapContents && Buffer . from ( mapContents ) . toString ( 'utf-8' ) ,
9191 } ;
9292 } ,
93+ // eslint-disable-next-line max-lines-per-function
9394 configureServer ( server ) {
9495 const originalssrTransform = server . ssrTransform ;
9596 server . ssrTransform = async ( code , map , url , originalCode ) => {
@@ -169,6 +170,8 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
169170 // Returning a function, installs middleware after the main transform middleware but
170171 // before the built-in HTML middleware
171172 return ( ) => {
173+ server . middlewares . use ( angularHtmlFallbackMiddleware ) ;
174+
172175 function angularSSRMiddleware (
173176 req : Connect . IncomingMessage ,
174177 res : ServerResponse ,
@@ -180,8 +183,8 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
180183 // Skip if path is not defined.
181184 ! url ||
182185 // Skip if path is like a file.
183- // NOTE: We use a regexp to mitigate against matching requests like: /browse/pl.0ef59752c0cd457dbf1391f08cbd936f
184- / ^ \. [ a - z ] { 2 , 4 } $ / i . test ( extname ( url . split ( '?' ) [ 0 ] ) )
186+ // NOTE: We use a mime type lookup to mitigate against matching requests like: /browse/pl.0ef59752c0cd457dbf1391f08cbd936f
187+ lookupMimeTypeFromRequest ( url )
185188 ) {
186189 next ( ) ;
187190
@@ -307,3 +310,34 @@ function pathnameWithoutBasePath(url: string, basePath: string): string {
307310 ? pathname . slice ( basePath . length - 1 )
308311 : pathname ;
309312}
313+
314+ function angularHtmlFallbackMiddleware (
315+ req : Connect . IncomingMessage ,
316+ res : ServerResponse ,
317+ next : Connect . NextFunction ,
318+ ) : void {
319+ // Similar to how it is handled in vite
320+ // https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/middlewares/htmlFallback.ts#L15C19-L15C45
321+ if (
322+ ( req . method === 'GET' || req . method === 'HEAD' ) &&
323+ ( ! req . url || ! lookupMimeTypeFromRequest ( req . url ) ) &&
324+ ( ! req . headers . accept ||
325+ req . headers . accept . includes ( 'text/html' ) ||
326+ req . headers . accept . includes ( 'text/*' ) ||
327+ req . headers . accept . includes ( '*/*' ) )
328+ ) {
329+ req . url = '/index.html' ;
330+ }
331+
332+ next ( ) ;
333+ }
334+
335+ function lookupMimeTypeFromRequest ( url : string ) : string | undefined {
336+ const extension = extname ( url . split ( '?' ) [ 0 ] ) ;
337+
338+ if ( extension === '.ico' ) {
339+ return 'image/x-icon' ;
340+ }
341+
342+ return extension && lookupMimeType ( extension ) ;
343+ }
0 commit comments