@@ -278,6 +278,8 @@ export type ProdServerOptions = {
278278 outDir ?: string ;
279279 /** Explicit App Router RSC entry path. Defaults to `<outDir>/server/index.js`. */
280280 rscEntryPath ?: string ;
281+ /** Directory containing server manifests, sidecars, and prerender artifacts. */
282+ serverDir ?: string ;
281283 /** Explicit Pages Router server entry path. Defaults to `<outDir>/server/entry.js`. */
282284 serverEntryPath ?: string ;
283285 /** Disable compression (default: false) */
@@ -1266,6 +1268,7 @@ export async function startProdServer(options: ProdServerOptions = {}) {
12661268 host = "0.0.0.0" ,
12671269 outDir = path . resolve ( "dist" ) ,
12681270 rscEntryPath : explicitRscEntryPath ,
1271+ serverDir : explicitServerDir ,
12691272 serverEntryPath : explicitServerEntryPath ,
12701273 noCompression = false ,
12711274 purpose,
@@ -1276,14 +1279,17 @@ export async function startProdServer(options: ProdServerOptions = {}) {
12761279 // Always resolve outDir to absolute to ensure dynamic import() works
12771280 const resolvedOutDir = path . resolve ( outDir ) ;
12781281 const clientDir = path . join ( resolvedOutDir , "client" ) ;
1282+ const serverDir = explicitServerDir
1283+ ? path . resolve ( explicitServerDir )
1284+ : path . join ( resolvedOutDir , "server" ) ;
12791285
12801286 // Detect build type
12811287 const rscEntryPath = explicitRscEntryPath
12821288 ? path . resolve ( explicitRscEntryPath )
1283- : path . join ( resolvedOutDir , "server" , "index.js" ) ;
1289+ : path . join ( serverDir , "index.js" ) ;
12841290 const serverEntryPath = explicitServerEntryPath
12851291 ? path . resolve ( explicitServerEntryPath )
1286- : path . join ( resolvedOutDir , "server" , "entry.js" ) ;
1292+ : path . join ( serverDir , "entry.js" ) ;
12871293 const isAppRouter = fs . existsSync ( rscEntryPath ) ;
12881294
12891295 if ( ! isAppRouter && ! fs . existsSync ( serverEntryPath ) ) {
@@ -1293,7 +1299,16 @@ export async function startProdServer(options: ProdServerOptions = {}) {
12931299 }
12941300
12951301 if ( isAppRouter ) {
1296- return startAppRouterServer ( { port, host, clientDir, rscEntryPath, compress, purpose, silent } ) ;
1302+ return startAppRouterServer ( {
1303+ port,
1304+ host,
1305+ clientDir,
1306+ serverDir,
1307+ rscEntryPath,
1308+ compress,
1309+ purpose,
1310+ silent,
1311+ } ) ;
12971312 }
12981313
12991314 return startPagesRouterServer ( {
@@ -1313,6 +1328,7 @@ type AppRouterServerOptions = {
13131328 port : number ;
13141329 host : string ;
13151330 clientDir : string ;
1331+ serverDir : string ;
13161332 rscEntryPath : string ;
13171333 compress : boolean ;
13181334 purpose ?: ProdServerOptions [ "purpose" ] ;
@@ -1547,11 +1563,11 @@ function installPagesClientAssets(options: {
15471563 * 4. Stream the Web Response back (with optional compression)
15481564 */
15491565async function startAppRouterServer ( options : AppRouterServerOptions ) {
1550- const { port, host, clientDir, rscEntryPath, compress, purpose, silent } = options ;
1566+ const { port, host, clientDir, serverDir , rscEntryPath, compress, purpose, silent } = options ;
15511567
15521568 // Load prerender secret written at build time by vinext:server-manifest plugin.
15531569 // Used to authenticate internal /__vinext/prerender/* HTTP endpoints.
1554- const prerenderSecret = readPrerenderSecret ( path . dirname ( rscEntryPath ) ) ;
1570+ const prerenderSecret = readPrerenderSecret ( serverDir ) ;
15551571
15561572 // Import the RSC handler. importServerEntryModule uses the bare file://
15571573 // URL so lazy chunks that import the entry back resolve to the same module
@@ -1586,7 +1602,7 @@ async function startAppRouterServer(options: AppRouterServerOptions) {
15861602 ? ( rscModule . __imageConfig as ImageConfig )
15871603 : undefined ;
15881604 if ( imageConfig === undefined ) {
1589- const imageConfigPath = path . join ( path . dirname ( rscEntryPath ) , "image-config.json" ) ;
1605+ const imageConfigPath = path . join ( serverDir , "image-config.json" ) ;
15901606 if ( fs . existsSync ( imageConfigPath ) ) {
15911607 try {
15921608 imageConfig = JSON . parse ( fs . readFileSync ( imageConfigPath , "utf-8" ) ) ;
@@ -1619,7 +1635,7 @@ async function startAppRouterServer(options: AppRouterServerOptions) {
16191635 // any pre-rendered page is a cache HIT instead of a full re-render.
16201636 const seedPrerenderedRoutes = resolveAppRouterPrerenderSeeder ( rscModule ) ;
16211637 const seededRoutes = await runWithServerEntryRequire ( rscEntryRequire , ( ) =>
1622- seedPrerenderedRoutes ( path . dirname ( rscEntryPath ) ) ,
1638+ seedPrerenderedRoutes ( serverDir ) ,
16231639 ) ;
16241640 if ( seededRoutes > 0 ) {
16251641 console . log (
0 commit comments