1
- import { existsSync } from 'node:fs' ;
1
+ import { existsSync , statSync } from 'node:fs' ;
2
2
import { basename , isAbsolute , posix , resolve , sep , win32 } from 'node:path' ;
3
3
4
4
import { getDirectoryFromWorkingDir } from '@storybook/core/common' ;
@@ -26,9 +26,25 @@ export async function useStatics(app: Polka.Polka, options: Options): Promise<vo
26
26
) ;
27
27
}
28
28
29
+ if ( existsSync ( staticPath ) && statSync ( staticPath ) . isFile ( ) ) {
30
+ // sirv doesn't support serving single files, so we need to pass the file's directory to sirv instead
31
+ const staticPathDir = resolve ( staticPath , '..' ) ;
32
+ const staticPathFile = basename ( staticPath ) ;
33
+ app . use ( targetEndpoint , ( req , res , next ) => {
34
+ // Rewrite the URL to match the file's name, ensuring that we only ever serve the file
35
+ // even when sirv is passed the full directory
36
+ req . url = `/${ staticPathFile } ` ;
37
+ sirvWorkaround ( staticPathDir , {
38
+ dev : true ,
39
+ etag : true ,
40
+ extensions : [ ] ,
41
+ } ) ( req , res , next ) ;
42
+ } ) ;
43
+ return ;
44
+ }
29
45
app . use (
30
46
targetEndpoint ,
31
- sirv ( staticPath , {
47
+ sirvWorkaround ( staticPath , {
32
48
dev : true ,
33
49
etag : true ,
34
50
extensions : [ ] ,
@@ -43,14 +59,38 @@ export async function useStatics(app: Polka.Polka, options: Options): Promise<vo
43
59
44
60
app . get (
45
61
`/${ basename ( faviconPath ) } ` ,
46
- sirv ( faviconPath , {
62
+ sirvWorkaround ( faviconPath , {
47
63
dev : true ,
48
64
etag : true ,
49
65
extensions : [ ] ,
50
66
} )
51
67
) ;
52
68
}
53
69
70
+ /**
71
+ * This is a workaround for sirv breaking when serving multiple directories on the same endpoint.
72
+ *
73
+ * @see https://github.com/lukeed/polka/issues/218
74
+ */
75
+ const sirvWorkaround : typeof sirv =
76
+ ( ...sirvArgs ) =>
77
+ ( req , res , next ) => {
78
+ // polka+sirv will modify the request URL, so we need to restore it after sirv is done
79
+ // req._parsedUrl is an internal construct used by both polka and sirv
80
+ // eslint-disable-next-line no-underscore-dangle
81
+ const originalParsedUrl = ( req as any ) . _parsedUrl ;
82
+
83
+ const maybeNext = next
84
+ ? ( ) => {
85
+ // eslint-disable-next-line no-underscore-dangle
86
+ ( req as any ) . _parsedUrl = originalParsedUrl ;
87
+ next ( ) ;
88
+ }
89
+ : undefined ;
90
+
91
+ sirv ( ...sirvArgs ) ( req , res , maybeNext ) ;
92
+ } ;
93
+
54
94
export const parseStaticDir = ( arg : string ) => {
55
95
// Split on last index of ':', for Windows compatibility (e.g. 'C:\some\dir:\foo')
56
96
const lastColonIndex = arg . lastIndexOf ( ':' ) ;
0 commit comments