Repository: vercel/next.js
Pull request: Turbopack: remove unneeded manifests for API routes

Closes PACK-5053

Changed files:
filename: crates/next-api/src/app.rs
patch: @@ -1162,30 +1162,33 @@ impl AppEndpoint {
             None,
             /// Emit the manifest for basic Next.js functionality (e.g. app-build-manifest.json)
             Minimal,
-            /// All manifests: `Minimal` plus client-references, next-dynamic, ...
+            /// All manifests: `Minimal` plus next-font, next-dynamic, ...
             Full,
         }
-        let (process_client_assets, process_ssr, emit_manifests) = match &this.ty {
-            AppEndpointType::Page { ty, .. } => (
-                true,
-                matches!(ty, AppPageEndpointType::Html),
-                if matches!(ty, AppPageEndpointType::Html) {
-                    EmitManifests::Full
-                } else {
-                    EmitManifests::None
-                },
-            ),
-            AppEndpointType::Route { .. } => (false, false, EmitManifests::Full),
-            AppEndpointType::Metadata { metadata } => (
-                false,
-                false,
-                if matches!(metadata, MetadataItem::Dynamic { .. }) {
-                    EmitManifests::Full
-                } else {
-                    EmitManifests::Minimal
-                },
-            ),
-        };
+        let (process_client_assets, process_ssr, emit_manifests, emit_rsc_manifests) =
+            match &this.ty {
+                AppEndpointType::Page { ty, .. } => (
+                    true,
+                    matches!(ty, AppPageEndpointType::Html),
+                    if matches!(ty, AppPageEndpointType::Html) {
+                        EmitManifests::Full
+                    } else {
+                        EmitManifests::None
+                    },
+                    matches!(ty, AppPageEndpointType::Html),
+                ),
+                AppEndpointType::Route { .. } => (false, false, EmitManifests::Minimal, true),
+                AppEndpointType::Metadata { metadata } => (
+                    false,
+                    false,
+                    if matches!(metadata, MetadataItem::Dynamic { .. }) {
+                        EmitManifests::Full
+                    } else {
+                        EmitManifests::Minimal
+                    },
+                    matches!(metadata, MetadataItem::Dynamic { .. }),
+                ),
+            };
 
         let node_root = project.node_root().owned().await?;
         let client_relative_path = project.client_relative_path().owned().await?;
@@ -1434,7 +1437,7 @@ impl AppEndpoint {
                 .runtime_chunking_context(process_client_assets, runtime),
         )
         .await?;
-        if emit_manifests == EmitManifests::Full {
+        if emit_rsc_manifests {
             server_assets.insert(server_action_manifest.manifest);
         }
 
@@ -1460,7 +1463,7 @@ impl AppEndpoint {
         // these references are important for turbotrace
         let mut client_reference_manifest = None;
 
-        if emit_manifests == EmitManifests::Full {
+        if emit_rsc_manifests {
             let entry_manifest =
                 ClientReferenceManifest::build_output(ClientReferenceManifestOptions {
                     node_root: node_root.clone(),
@@ -1482,7 +1485,8 @@ impl AppEndpoint {
                 middleware_assets.insert(entry_manifest);
             }
             client_reference_manifest = Some(entry_manifest);
-
+        }
+        if emit_manifests == EmitManifests::Full {
             let next_font_manifest_output = create_font_manifest(
                 project.client_root().owned().await?,
                 node_root.clone(),
@@ -1504,11 +1508,16 @@ impl AppEndpoint {
                 //
                 // they are created in `setup-dev-bundler.ts`
                 let mut file_paths_from_root = fxindexset![
-                    rcstr!("server/server-reference-manifest.js"),
                     rcstr!("server/middleware-build-manifest.js"),
-                    rcstr!("server/next-font-manifest.js"),
                     rcstr!("server/interception-route-rewrite-manifest.js"),
                 ];
+                if emit_manifests == EmitManifests::Full {
+                    file_paths_from_root.insert(rcstr!("server/next-font-manifest.js"));
+                };
+                if emit_rsc_manifests {
+                    file_paths_from_root.insert(rcstr!("server/server-reference-manifest.js"));
+                }
+
                 let mut wasm_paths_from_root = fxindexset![];
 
                 let node_root_value = node_root.clone();
@@ -1556,7 +1565,8 @@ impl AppEndpoint {
                     file_paths_from_root.extend(
                         get_js_paths_from_root(&node_root_value, &loadable_manifest_output).await?,
                     );
-
+                }
+                if emit_manifests != EmitManifests::None {
                     // create middleware manifest
                     let named_regex = get_named_middleware_regex(&app_entry.pathname);
                     let matchers = MiddlewareMatcher {

filename: crates/next-api/src/pages.rs
patch: @@ -684,24 +684,26 @@ enum PageEndpointType {
 }
 
 #[derive(
-    Copy,
-    Clone,
-    Serialize,
-    Deserialize,
-    PartialEq,
-    Eq,
-    Hash,
-    Debug,
-    TaskInput,
-    TraceRawVcs,
-    NonLocalValue,
+    Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, TaskInput, TraceRawVcs,
 )]
 enum SsrChunkType {
     Page,
     Data,
     Api,
 }
 
+#[derive(
+    Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, TaskInput, TraceRawVcs,
+)]
+enum EmitManifests {
+    /// Don't emit any manifests
+    None,
+    /// Emit the manifest for basic Next.js functionality (e.g. pages-manifest.json)
+    Minimal,
+    /// All manifests: `Minimal` plus server-reference-manifest, next/font, next/dynamic
+    Full,
+}
+
 #[turbo_tasks::value_impl]
 impl PageEndpoint {
     #[turbo_tasks::function]
@@ -982,6 +984,7 @@ impl PageEndpoint {
     async fn internal_ssr_chunk(
         self: Vc<Self>,
         ty: SsrChunkType,
+        emit_manifests: EmitManifests,
         node_path: FileSystemPath,
         node_chunking_context: Vc<NodeJsChunkingContext>,
         edge_chunking_context: Vc<Box<dyn ChunkingContext>>,
@@ -1147,19 +1150,22 @@ impl PageEndpoint {
                     .await?
                     .is_production()
                 {
-                    let loadable_manifest_output =
-                        self.react_loadable_manifest(*dynamic_import_entries, NextRuntime::NodeJs);
+                    let additional_assets = if emit_manifests == EmitManifests::Full {
+                        self.react_loadable_manifest(*dynamic_import_entries, NextRuntime::NodeJs)
+                            .await?
+                            .iter()
+                            .map(|m| **m)
+                            .collect()
+                    } else {
+                        vec![]
+                    };
 
                     ResolvedVc::cell(Some(ResolvedVc::upcast(
                         NftJsonAsset::new(
                             project,
                             Some(this.original_name.clone()),
                             *ssr_entry_chunk,
-                            loadable_manifest_output
-                                .await?
-                                .iter()
-                                .map(|m| **m)
-                                .collect(),
+                            additional_assets,
                         )
                         .to_resolved()
                         .await?,
@@ -1185,11 +1191,12 @@ impl PageEndpoint {
     }
 
     #[turbo_tasks::function]
-    async fn ssr_chunk(self: Vc<Self>) -> Result<Vc<SsrChunk>> {
+    async fn ssr_chunk(self: Vc<Self>, emit_manifests: EmitManifests) -> Result<Vc<SsrChunk>> {
         let this = self.await?;
         let project = this.pages_project.project();
         Ok(self.internal_ssr_chunk(
             SsrChunkType::Page,
+            emit_manifests,
             this.pages_project
                 .project()
                 .node_root()
@@ -1203,10 +1210,11 @@ impl PageEndpoint {
     }
 
     #[turbo_tasks::function]
-    async fn ssr_data_chunk(self: Vc<Self>) -> Result<Vc<SsrChunk>> {
+    async fn ssr_data_chunk(self: Vc<Self>, emit_manifests: EmitManifests) -> Result<Vc<SsrChunk>> {
         let this = self.await?;
         Ok(self.internal_ssr_chunk(
             SsrChunkType::Data,
+            emit_manifests,
             this.pages_project
                 .project()
                 .node_root()
@@ -1220,10 +1228,11 @@ impl PageEndpoint {
     }
 
     #[turbo_tasks::function]
-    async fn api_chunk(self: Vc<Self>) -> Result<Vc<SsrChunk>> {
+    async fn api_chunk(self: Vc<Self>, emit_manifests: EmitManifests) -> Result<Vc<SsrChunk>> {
         let this = self.await?;
         Ok(self.internal_ssr_chunk(
             SsrChunkType::Api,
+            emit_manifests,
             this.pages_project
                 .project()
                 .node_root()
@@ -1348,6 +1357,12 @@ impl PageEndpoint {
         let mut server_assets = vec![];
         let mut client_assets = vec![];
 
+        let emit_manifests = match this.ty {
+            PageEndpointType::Html | PageEndpointType::SsrOnly => EmitManifests::Full,
+            PageEndpointType::Api => EmitManifests::Minimal,
+            PageEndpointType::Data => EmitManifests::None,
+        };
+
         let ssr_chunk = match this.ty {
             PageEndpointType::Html => {
                 let client_chunks = *self.client_chunks().await?.assets;
@@ -1361,13 +1376,12 @@ impl PageEndpoint {
                 client_assets.push(page_loader);
                 server_assets.push(build_manifest);
                 server_assets.push(client_build_manifest);
-                self.ssr_chunk()
+                self.ssr_chunk(emit_manifests)
             }
-            PageEndpointType::Data => self.ssr_data_chunk(),
-            PageEndpointType::Api => self.api_chunk(),
-            PageEndpointType::SsrOnly => self.ssr_chunk(),
+            PageEndpointType::Data => self.ssr_data_chunk(emit_manifests),
+            PageEndpointType::Api => self.api_chunk(emit_manifests),
+            PageEndpointType::SsrOnly => self.ssr_chunk(emit_manifests),
         };
-        let emit_manifests = !matches!(this.ty, PageEndpointType::Data);
 
         let pathname = &this.pathname;
         let original_name = &this.original_name;
@@ -1376,18 +1390,21 @@ impl PageEndpoint {
 
         let manifest_path_prefix = get_asset_prefix_from_pathname(pathname);
         let node_root = this.pages_project.project().node_root().owned().await?;
-        let next_font_manifest_output = create_font_manifest(
-            this.pages_project.project().client_root().owned().await?,
-            node_root.clone(),
-            this.pages_project.pages_dir().owned().await?,
-            original_name,
-            &manifest_path_prefix,
-            pathname,
-            *client_assets,
-            false,
-        )
-        .await?;
-        server_assets.push(next_font_manifest_output);
+
+        if emit_manifests == EmitManifests::Full {
+            let next_font_manifest_output = create_font_manifest(
+                this.pages_project.project().client_root().owned().await?,
+                node_root.clone(),
+                this.pages_project.pages_dir().owned().await?,
+                original_name,
+                &manifest_path_prefix,
+                pathname,
+                *client_assets,
+                false,
+            )
+            .await?;
+            server_assets.push(next_font_manifest_output);
+        }
 
         if *this
             .pages_project
@@ -1425,10 +1442,11 @@ impl PageEndpoint {
                     server_assets.push(*server_asset_trace_file);
                 }
 
-                if emit_manifests {
+                if emit_manifests != EmitManifests::None {
                     let pages_manifest = self.pages_manifest(*entry).to_resolved().await?;
                     server_assets.push(pages_manifest);
-
+                }
+                if emit_manifests == EmitManifests::Full {
                     let loadable_manifest_output =
                         self.react_loadable_manifest(*dynamic_import_entries, NextRuntime::NodeJs);
                     server_assets.extend(loadable_manifest_output.await?.iter().copied());
@@ -1446,47 +1464,48 @@ impl PageEndpoint {
                 ref regions,
             } => {
                 let node_root = this.pages_project.project().node_root().owned().await?;
-                if emit_manifests {
+                if emit_manifests != EmitManifests::None {
+                    // the next-edge-ssr-loader templates expect the manifests to be stored in
+                    // global variables defined in these files
+                    //
+                    // they are created in `setup-dev-bundler.ts`
+                    let mut file_paths_from_root = if emit_manifests == EmitManifests::Full {
+                        fxindexset![
+                            rcstr!("server/server-reference-manifest.js"),
+                            rcstr!("server/middleware-build-manifest.js"),
+                            rcstr!("server/next-font-manifest.js"),
+                        ]
+                    } else {
+                        fxindexset![]
+                    };
+
                     let files_value = files.await?;
                     if let Some(&file) = files_value.first() {
                         let pages_manifest = self.pages_manifest(*file).to_resolved().await?;
                         server_assets.push(pages_manifest);
                     }
                     server_assets.extend(files_value.iter().copied());
-
-                    let loadable_manifest_output = self
-                        .react_loadable_manifest(*dynamic_import_entries, NextRuntime::Edge)
-                        .await?;
-                    server_assets.extend(loadable_manifest_output.iter().copied());
-
-                    // the next-edge-ssr-loader templates expect the manifests to be stored in
-                    // global variables defined in these files
-                    //
-                    // they are created in `setup-dev-bundler.ts`
-                    let mut file_paths_from_root = vec![
-                        rcstr!("server/server-reference-manifest.js"),
-                        rcstr!("server/middleware-build-manifest.js"),
-                        rcstr!("server/next-font-manifest.js"),
-                    ];
-                    let mut wasm_paths_from_root = fxindexset![];
-
-                    let node_root_value = node_root.clone();
-
-                    file_paths_from_root.extend(
-                        get_js_paths_from_root(&node_root_value, &loadable_manifest_output).await?,
-                    );
-
                     file_paths_from_root
-                        .extend(get_js_paths_from_root(&node_root_value, &files_value).await?);
+                        .extend(get_js_paths_from_root(&node_root, &files_value).await?);
+
+                    if emit_manifests == EmitManifests::Full {
+                        let loadable_manifest_output = self
+                            .react_loadable_manifest(*dynamic_import_entries, NextRuntime::Edge)
+                            .await?;
+                        server_assets.extend(loadable_manifest_output.iter().copied());
+                        file_paths_from_root.extend(
+                            get_js_paths_from_root(&node_root, &loadable_manifest_output).await?,
+                        );
+                    }
 
                     let all_output_assets = all_assets_from_entries(*files).await?;
 
-                    wasm_paths_from_root.extend(
-                        get_wasm_paths_from_root(&node_root_value, &all_output_assets).await?,
-                    );
+                    let mut wasm_paths_from_root = fxindexset![];
+                    wasm_paths_from_root
+                        .extend(get_wasm_paths_from_root(&node_root, &all_output_assets).await?);
 
                     let all_assets =
-                        get_asset_paths_from_root(&node_root_value, &all_output_assets).await?;
+                        get_asset_paths_from_root(&node_root, &all_output_assets).await?;
 
                     let named_regex = get_named_middleware_regex(pathname).into();
                     let matchers = MiddlewareMatcher {
@@ -1507,7 +1526,7 @@ impl PageEndpoint {
                     };
 
                     let edge_function_definition = EdgeFunctionDefinition {
-                        files: file_paths_from_root,
+                        files: file_paths_from_root.into_iter().collect(),
                         wasm: wasm_paths_to_bindings(wasm_paths_from_root).await?,
                         assets: paths_to_bindings(all_assets),
                         name: pathname.clone(),