File tree Expand file tree Collapse file tree
test/production/next-server-nft Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -74,18 +74,24 @@ enum ServerNftType {
7474
7575#[ turbo_tasks:: function]
7676pub async fn next_server_nft_assets ( project : Vc < Project > ) -> Result < Vc < OutputAssets > > {
77- if * project. next_config ( ) . is_using_adapter ( ) . await ? {
77+ let is_standalone = * project. next_config ( ) . is_standalone ( ) . await ?;
78+
79+ if * project. next_config ( ) . is_using_adapter ( ) . await ? && !is_standalone {
7880 // When using an adapter, `next-server.js.nft.json` / `next-minimal-server.js.nft.json` are
7981 // not needed: they exist for `output: 'standalone'` (see `copyTracedFiles`), while an
8082 // adapter assembles the deployment from the per-endpoint NFTs in build-complete.ts. What
8183 // those two files trace on top of the endpoints - the `styled-jsx` modules the require hook
8284 // needs at runtime - is part of every endpoint's trace via
8385 // `Project::additional_traced_modules`, so nothing is lost here.
86+ //
87+ // The exception is `output: 'standalone'` configured alongside an adapter:
88+ // `copyTracedFiles` reads `next-server.js.nft.json` unconditionally whenever standalone
89+ // output is requested (adapter or not), so suppressing the pair crashes the build
90+ // (see #96646).
8491 return Ok ( Vc :: cell ( vec ! [ ] ) ) ;
8592 }
8693
8794 let has_next_support = * project. ci_has_next_support ( ) . await ?;
88- let is_standalone = * project. next_config ( ) . is_standalone ( ) . await ?;
8995
9096 let minimal = ResolvedVc :: upcast (
9197 ServerNftJsonAsset :: new ( project, ServerNftType :: Minimal )
Original file line number Diff line number Diff line change @@ -723,5 +723,41 @@ async function readNormalizedNFT(next, name) {
723723 ` )
724724 } )
725725 } )
726+
727+ describe ( 'with adapters and output:standalone' , ( ) => {
728+ const { next, skipped } = nextTestSetup ( {
729+ files : __dirname ,
730+ dependencies : {
731+ typescript : '5.9.2' ,
732+ } ,
733+ nextConfig : {
734+ output : 'standalone' ,
735+ adapterPath : path . join ( __dirname , './my-adapter.mjs' ) ,
736+ } ,
737+ } )
738+
739+ if ( skipped ) {
740+ return
741+ }
742+
743+ // Regression test for #96646: with an adapter configured, the whole-app server NFTs were
744+ // suppressed while `copyTracedFiles` (which runs for `output: 'standalone'`, adapter or
745+ // not) still reads `next-server.js.nft.json` unconditionally — crashing the build with
746+ // ENOENT.
747+ it ( 'should emit both whole-app server NFTs and complete the build' , async ( ) => {
748+ const serverTrace = await next . readJSON ( '.next/next-server.js.nft.json' )
749+ expect ( Array . isArray ( serverTrace . files ) ) . toBe ( true )
750+ expect ( serverTrace . files . length ) . toBeGreaterThan ( 0 )
751+
752+ const minimalTrace = await next . readJSON (
753+ '.next/next-minimal-server.js.nft.json'
754+ )
755+ expect ( Array . isArray ( minimalTrace . files ) ) . toBe ( true )
756+
757+ // The adapter still ran (my-adapter.mjs writes build-complete.json).
758+ const buildComplete = await next . readJSON ( 'build-complete.json' )
759+ expect ( buildComplete ) . toBeTruthy ( )
760+ } )
761+ } )
726762 }
727763)
You can’t perform that action at this time.
0 commit comments