@@ -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
@@ -307,3 +310,34 @@ function pathnameWithoutBasePath(url: string, basePath: string): string {
307
310
? pathname . slice ( basePath . length - 1 )
308
311
: pathname ;
309
312
}
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