@@ -2,13 +2,17 @@ import { FileSystemRouter } from "bun";
22import { NJSON } from "next-json" ;
33import { statSync } from "node:fs" ;
44import { join , relative } from "node:path" ;
5+ import { preloadModule } from "react-dom" ;
56import { renderToReadableStream } from "react-dom/server" ;
67import { ClientOnlyError } from "./client" ;
8+ import { MetaContext , PreloadModule } from "./preload" ;
79
810export class StaticRouters {
911 readonly server : FileSystemRouter ;
1012 readonly client : FileSystemRouter ;
13+ readonly #routes: Map < string , string > ;
1114 readonly #routes_dump: string ;
15+ readonly #dependencies: Record < string , string [ ] > ;
1216 readonly #hashed: Record < string , string > ;
1317
1418 constructor (
@@ -24,17 +28,19 @@ export class StaticRouters {
2428 dir : join ( baseDir , buildDir , pageDir ) ,
2529 style : "nextjs" ,
2630 } ) ;
27- this . #hashed = require ( join ( baseDir , buildDir , ".meta.json" ) ) . hashed ;
28- this . #routes_dump = NJSON . stringify (
29- Object . fromEntries (
30- Object . entries ( this . client . routes ) . map ( ( [ path , filePath ] ) => {
31- let target = "/" + relative ( join ( baseDir , buildDir ) , filePath ) ;
32- if ( this . #hashed[ target ] ) target += `?${ this . #hashed[ target ] } ` ;
33- return [ path , target ] ;
34- } )
35- ) ,
36- { omitStack : true }
31+ const parsed = require ( join ( baseDir , buildDir , ".meta.json" ) ) ;
32+ this . #hashed = parsed . hashed ;
33+ this . #dependencies = parsed . dependencies ;
34+ this . #routes = new Map (
35+ Object . entries ( this . client . routes ) . map ( ( [ path , filePath ] ) => {
36+ let target = "/" + relative ( join ( baseDir , buildDir ) , filePath ) ;
37+ if ( this . #hashed[ target ] ) target += `?${ this . #hashed[ target ] } ` ;
38+ return [ path , target ] ;
39+ } )
3740 ) ;
41+ this . #routes_dump = NJSON . stringify ( Object . fromEntries ( this . #routes) , {
42+ omitStack : true ,
43+ } ) ;
3844 }
3945
4046 async serve < T = void > (
@@ -101,7 +107,14 @@ export class StaticRouters {
101107 }
102108 const stream = await renderToReadableStream (
103109 < Shell route = { serverSide . pathname + search } { ...staticProps } { ...result } >
104- < module . default { ...result ?. props } />
110+ < MetaContext . Provider
111+ value = { { hash : this . #hashed, dependencies : this . #dependencies } }
112+ >
113+ < PreloadModule
114+ module = { this . #routes. get ( serverSide . pathname ) ! . split ( "?" ) [ 0 ] }
115+ />
116+ < module . default { ...result ?. props } />
117+ </ MetaContext . Provider >
105118 </ Shell > ,
106119 {
107120 signal : request . signal ,
@@ -140,6 +153,34 @@ export class StaticRouters {
140153 }
141154}
142155
156+ function DirectPreloadModule ( {
157+ target,
158+ dependencies,
159+ } : {
160+ target : string ;
161+ dependencies : Record < string , string [ ] > ;
162+ } ) {
163+ preloadModule ( target , { as : "script" } ) ;
164+ preloadModule ( target , { as : "script" } ) ;
165+ for ( const dep of walkDependencies ( target , dependencies ) ) {
166+ preloadModule ( dep , { as : "script" } ) ;
167+ preloadModule ( dep , { as : "script" } ) ;
168+ }
169+ return null ;
170+ }
171+
172+ function * walkDependencies (
173+ target : string ,
174+ dependencies : Record < string , string [ ] >
175+ ) : Generator < string > {
176+ if ( dependencies [ target ] ) {
177+ for ( const dep of dependencies [ target ] ) {
178+ yield dep ;
179+ yield * walkDependencies ( dep , dependencies ) ;
180+ }
181+ }
182+ }
183+
143184export async function serveFromDir ( config : {
144185 directory : string ;
145186 path : string ;
0 commit comments