1
1
import { FileSystemRouter } from "bun" ;
2
2
import { NJSON } from "next-json" ;
3
- import { statSync } from "node:fs" ;
3
+ import { readFileSync , statSync } from "node:fs" ;
4
4
import { join , relative } from "node:path" ;
5
- import { preloadModule } from "react-dom" ;
6
5
import { renderToReadableStream } from "react-dom/server" ;
7
6
import { ClientOnlyError } from "./client" ;
8
7
import { MetaContext , PreloadModule } from "./preload" ;
9
8
10
9
export class StaticRouters {
11
- readonly server : FileSystemRouter ;
12
- readonly client : FileSystemRouter ;
13
- readonly #routes: Map < string , string > ;
14
- readonly #routes_dump: string ;
15
- readonly #dependencies: Record < string , string [ ] > ;
16
- readonly #hashed: Record < string , string > ;
10
+ server ! : FileSystemRouter ;
11
+ client ! : FileSystemRouter ;
12
+ #routes! : Map < string , string > ;
13
+ #routes_dump! : string ;
14
+ #dependencies! : Record < string , string [ ] > ;
15
+ #hashed! : Record < string , string > ;
16
+ #cached = new Set < string > ( ) ;
17
17
18
18
constructor (
19
19
public baseDir : string ,
20
20
public buildDir = ".build" ,
21
21
public pageDir = "pages"
22
22
) {
23
+ this . reload ( ) ;
24
+ }
25
+
26
+ reload ( excludes : RegExp [ ] = [ ] ) {
27
+ const { baseDir, pageDir, buildDir } = this ;
28
+ const metafile = Bun . fileURLToPath (
29
+ import . meta. resolve ( join ( baseDir , buildDir , ".meta.json" ) )
30
+ ) ;
31
+ delete require . cache [ metafile ] ;
32
+ if ( this . #cached. size ) {
33
+ for ( const cached of this . #cached) {
34
+ delete require . cache [ cached ] ;
35
+ for ( const dep of scanCacheDependencies ( cached , excludes ) ) {
36
+ delete require . cache [ dep ] ;
37
+ }
38
+ }
39
+ this . #cached. clear ( ) ;
40
+ }
23
41
this . server = new FileSystemRouter ( {
24
42
dir : join ( baseDir , pageDir ) ,
25
43
style : "nextjs" ,
@@ -28,7 +46,7 @@ export class StaticRouters {
28
46
dir : join ( baseDir , buildDir , pageDir ) ,
29
47
style : "nextjs" ,
30
48
} ) ;
31
- const parsed = require ( join ( baseDir , buildDir , ".meta.json" ) ) ;
49
+ const parsed = require ( metafile ) ;
32
50
this . #hashed = parsed . hashed ;
33
51
this . #dependencies = parsed . dependencies ;
34
52
this . #routes = new Map (
@@ -83,7 +101,8 @@ export class StaticRouters {
83
101
"No client-side script found for server-side component: " +
84
102
serverSide . filePath
85
103
) ;
86
- const module = await import ( serverSide . filePath ) ;
104
+ const module = require ( serverSide . filePath ) ;
105
+ this . #cached. add ( serverSide . filePath ) ;
87
106
const result = await module . getServerSideProps ?.( {
88
107
params : serverSide . params ,
89
108
req : request ,
@@ -156,32 +175,36 @@ export class StaticRouters {
156
175
}
157
176
}
158
177
159
- function DirectPreloadModule ( {
160
- target,
161
- dependencies,
162
- } : {
163
- target : string ;
164
- dependencies : Record < string , string [ ] > ;
165
- } ) {
166
- preloadModule ( target , { as : "script" } ) ;
167
- preloadModule ( target , { as : "script" } ) ;
168
- for ( const dep of walkDependencies ( target , dependencies ) ) {
169
- preloadModule ( dep , { as : "script" } ) ;
170
- preloadModule ( dep , { as : "script" } ) ;
171
- }
172
- return null ;
173
- }
174
-
175
- function * walkDependencies (
178
+ function * scanCacheDependencies (
176
179
target : string ,
177
- dependencies : Record < string , string [ ] >
180
+ excludes : RegExp [ ] = [ ]
178
181
) : Generator < string > {
179
- if ( dependencies [ target ] ) {
180
- for ( const dep of dependencies [ target ] ) {
181
- yield dep ;
182
- yield * walkDependencies ( dep , dependencies ) ;
182
+ try {
183
+ const imports = new Bun . Transpiler ( {
184
+ loader : target . endsWith ( ".tsx" )
185
+ ? "tsx"
186
+ : target . endsWith ( ".ts" )
187
+ ? "ts"
188
+ : "jsx" ,
189
+ } ) . scanImports ( readFileSync ( target ) ) ;
190
+ for ( const imp of imports ) {
191
+ if ( imp . kind === "import-statement" ) {
192
+ const path = Bun . fileURLToPath ( import . meta. resolve ( imp . path , target ) ) ;
193
+ if (
194
+ path . includes ( "/node_modules/" ) ||
195
+ excludes . some ( ( x ) => path . match ( x ) )
196
+ )
197
+ continue ;
198
+ const resolved = Object . keys ( require . cache ) . find ( ( x ) =>
199
+ x . startsWith ( path )
200
+ ) ;
201
+ if ( resolved ) {
202
+ yield resolved ;
203
+ yield * scanCacheDependencies ( resolved , excludes ) ;
204
+ }
205
+ }
183
206
}
184
- }
207
+ } catch { }
185
208
}
186
209
187
210
export async function serveFromDir ( config : {
0 commit comments