@@ -90,6 +90,7 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
90
90
map : mapContents && Buffer . from ( mapContents ) . toString ( 'utf-8' ) ,
91
91
} ;
92
92
} ,
93
+ // eslint-disable-next-line max-lines-per-function
93
94
configureServer ( server ) {
94
95
const originalssrTransform = server . ssrTransform ;
95
96
server . ssrTransform = async ( code , map , url , originalCode ) => {
@@ -169,6 +170,8 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
169
170
// Returning a function, installs middleware after the main transform middleware but
170
171
// before the built-in HTML middleware
171
172
return ( ) => {
173
+ server . middlewares . use ( angularHtmlFallbackMiddleware ) ;
174
+
172
175
function angularSSRMiddleware (
173
176
req : Connect . IncomingMessage ,
174
177
res : ServerResponse ,
@@ -180,8 +183,8 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
180
183
// Skip if path is not defined.
181
184
! url ||
182
185
// 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 )
185
188
) {
186
189
next ( ) ;
187
190
@@ -306,3 +309,34 @@ function pathnameWithoutBasePath(url: string, basePath: string): string {
306
309
? pathname . slice ( basePath . length - 1 )
307
310
: pathname ;
308
311
}
312
+
313
+ function angularHtmlFallbackMiddleware (
314
+ req : Connect . IncomingMessage ,
315
+ res : ServerResponse ,
316
+ next : Connect . NextFunction ,
317
+ ) : void {
318
+ // Similar to how it is handled in vite
319
+ // https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/middlewares/htmlFallback.ts#L15C19-L15C45
320
+ if (
321
+ ( req . method === 'GET' || req . method === 'HEAD' ) &&
322
+ ( ! req . url || ! lookupMimeTypeFromRequest ( req . url ) ) &&
323
+ ( ! req . headers . accept ||
324
+ req . headers . accept . includes ( 'text/html' ) ||
325
+ req . headers . accept . includes ( 'text/*' ) ||
326
+ req . headers . accept . includes ( '*/*' ) )
327
+ ) {
328
+ req . url = '/index.html' ;
329
+ }
330
+
331
+ next ( ) ;
332
+ }
333
+
334
+ function lookupMimeTypeFromRequest ( url : string ) : string | undefined {
335
+ const extension = extname ( url . split ( '?' ) [ 0 ] ) ;
336
+
337
+ if ( extension === '.ico' ) {
338
+ return 'image/x-icon' ;
339
+ }
340
+
341
+ return extension && lookupMimeType ( extension ) ;
342
+ }
0 commit comments