1
- import { FileSystemRouter } from "bun" ;
1
+ import { FileSystemRouter , type BunFile } from "bun" ;
2
2
import { NJSON } from "next-json" ;
3
3
import { readFileSync , statSync } from "node:fs" ;
4
- import { join , relative } from "node:path" ;
4
+ import { join , relative , normalize } from "node:path" ;
5
5
import { renderToReadableStream } from "react-dom/server" ;
6
6
import { ClientOnlyError } from "./client" ;
7
7
import { MetaContext , PreloadModule } from "./preload" ;
@@ -14,12 +14,25 @@ export class StaticRouters {
14
14
#dependencies! : Record < string , string [ ] > ;
15
15
#hashed! : Record < string , string > ;
16
16
#cached = new Set < string > ( ) ;
17
+ #static_cache: StaticFileCache ;
18
+ public baseDir : string ;
19
+ public buildDir = ".build" ;
20
+ public pageDir = "pages" ;
17
21
18
22
constructor (
19
- public baseDir : string ,
20
- public buildDir = ".build" ,
21
- public pageDir = "pages"
23
+ base : string ,
24
+ {
25
+ buildDir = ".build" ,
26
+ pageDir = "pages" ,
27
+ } : {
28
+ buildDir ?: string ;
29
+ pageDir ?: string ;
30
+ } = { }
22
31
) {
32
+ this . baseDir = base ;
33
+ this . buildDir = buildDir ;
34
+ this . pageDir = pageDir ;
35
+ this . #static_cache = new StaticFileCache ( join ( base , buildDir ) ) ;
23
36
this . reload ( ) ;
24
37
}
25
38
@@ -59,6 +72,7 @@ export class StaticRouters {
59
72
this . #routes_dump = NJSON . stringify ( Object . fromEntries ( this . #routes) , {
60
73
omitStack : true ,
61
74
} ) ;
75
+ this . #static_cache. reset ( ) ;
62
76
}
63
77
64
78
async serve < T = void > (
@@ -87,12 +101,10 @@ export class StaticRouters {
87
101
}
88
102
) : Promise < Response | null > {
89
103
const { pathname, search } = new URL ( request . url ) ;
90
- const staticResponse = await serveFromDir ( {
91
- directory : this . buildDir ,
92
- path : pathname ,
93
- } ) ;
94
- if ( staticResponse )
95
- return new Response ( staticResponse , { headers : staticHeaders } ) ;
104
+ const file = this . #static_cache. match ( pathname ) ;
105
+ if ( file ) {
106
+ return new Response ( file , { headers : staticHeaders } ) ;
107
+ }
96
108
const serverSide = this . server . match ( request ) ;
97
109
if ( ! serverSide ) return null ;
98
110
const clientSide = this . client . match ( request ) ;
@@ -206,6 +218,29 @@ function* scanCacheDependencies(
206
218
} catch { }
207
219
}
208
220
221
+ export class StaticFileCache {
222
+ #cache = new Map < string , BunFile > ( ) ;
223
+ constructor ( public base : string ) { }
224
+ reset ( ) {
225
+ this . #cache. clear ( ) ;
226
+ }
227
+ match ( pathname : string ) : BunFile | undefined {
228
+ if ( this . #cache. has ( pathname ) ) {
229
+ return this . #cache. get ( pathname ) ! ;
230
+ }
231
+ const final = join ( this . base , pathname ) ;
232
+ try {
233
+ const stat = statSync ( final ) ;
234
+ if ( stat ?. isFile ( ) ) {
235
+ const file = Bun . file ( final ) ;
236
+ this . #cache. set ( pathname , file ) ;
237
+ return file ;
238
+ }
239
+ } catch { }
240
+ }
241
+ }
242
+
243
+ /** @deprecated */
209
244
export async function serveFromDir ( config : {
210
245
directory : string ;
211
246
path : string ;
0 commit comments