diff --git a/packages/next-swc/crates/next-core/src/app_segment_config.rs b/packages/next-swc/crates/next-core/src/app_segment_config.rs index 4b4a2db547612..9b815d44f8d2c 100644 --- a/packages/next-swc/crates/next-core/src/app_segment_config.rs +++ b/packages/next-swc/crates/next-core/src/app_segment_config.rs @@ -8,7 +8,7 @@ use turbo_tasks_fs::FileSystemPath; use turbopack_binding::{ swc::core::{ common::{source_map::Pos, Span, Spanned, GLOBALS}, - ecma::ast::{Expr, Ident, Program}, + ecma::ast::{Decl, Expr, FnExpr, Ident, Program}, }, turbopack::{ core::{ @@ -74,8 +74,8 @@ pub struct NextSegmentConfig { pub preferred_region: Option>, pub experimental_ppr: Option, /// Wether these metadata exports are defined in the source file. - pub generate_image_metadata: Option, - pub generate_sitemaps: Option, + pub generate_image_metadata: bool, + pub generate_sitemaps: bool, } #[turbo_tasks::value_impl] @@ -277,22 +277,35 @@ pub async fn parse_segment_config_from_source( let mut config = NextSegmentConfig::default(); for item in &module_ast.body { - let Some(decl) = item + let Some(export_decl) = item .as_module_decl() .and_then(|mod_decl| mod_decl.as_export_decl()) - .and_then(|export_decl| export_decl.decl.as_var()) else { continue; }; - for decl in &decl.decls { - let Some(ident) = decl.name.as_ident().map(|ident| ident.deref()) else { - continue; - }; + match &export_decl.decl { + Decl::Var(var_decl) => { + for decl in &var_decl.decls { + let Some(ident) = decl.name.as_ident().map(|ident| ident.deref()) else { + continue; + }; - if let Some(init) = decl.init.as_ref() { - parse_config_value(source, &mut config, ident, init, eval_context); + if let Some(init) = decl.init.as_ref() { + parse_config_value(source, &mut config, ident, init, eval_context); + } + } } + Decl::Fn(fn_decl) => { + let ident = &fn_decl.ident; + // create an empty expression of {}, we don't need init for function + let init = Expr::Fn(FnExpr { + ident: None, + function: fn_decl.function.clone(), + }); + parse_config_value(source, &mut config, ident, &init, eval_context); + } + _ => {} } } config @@ -439,10 +452,10 @@ fn parse_config_value( // Match exported generateImageMetadata function and generateSitemaps function, and pass // them to config. "generateImageMetadata" => { - config.generate_image_metadata = Some(true); + config.generate_image_metadata = true; } "generateSitemaps" => { - config.generate_sitemaps = Some(true); + config.generate_sitemaps = true; } "experimental_ppr" => { let value = eval_context.eval(init); diff --git a/packages/next-swc/crates/next-core/src/next_app/metadata/route.rs b/packages/next-swc/crates/next-core/src/next_app/metadata/route.rs index fe9480a31d724..0e7b6b36bdcee 100644 --- a/packages/next-swc/crates/next-core/src/next_app/metadata/route.rs +++ b/packages/next-swc/crates/next-core/src/next_app/metadata/route.rs @@ -35,6 +35,7 @@ pub async fn get_app_metadata_route_source( page: AppPage, mode: NextMode, metadata: MetadataItem, + is_multi_dynamic: bool, ) -> Result>> { Ok(match metadata { MetadataItem::Static { path } => static_route_source(mode, path), @@ -45,7 +46,7 @@ pub async fn get_app_metadata_route_source( if stem == "robots" || stem == "manifest" { dynamic_text_route_source(path) } else if stem == "sitemap" { - dynamic_site_map_route_source(mode, path, page) + dynamic_site_map_route_source(mode, path, page, is_multi_dynamic) } else { dynamic_image_route_source(path) } @@ -76,17 +77,20 @@ pub async fn get_app_metadata_route_entry( // config.generateImageMetadata is defined let is_multi_dynamic: bool = if Some(segment_config).is_some() { let config = segment_config.await.unwrap(); - config.generate_sitemaps.is_some() || config.generate_image_metadata.is_some() + config.generate_sitemaps || config.generate_image_metadata } else { false }; + let origin_page = page.clone(); // remove the last /route segment of page page.0.pop(); let _ = if is_multi_dynamic { // push /[__metadata_id__] to the page + page.push(PageSegment::Dynamic("__metadata_id__".into())) + // Ok(()) } else { // if page last segment is sitemap, change to sitemap.xml if page.last() == Some(&PageSegment::Static("sitemap".into())) { @@ -99,11 +103,12 @@ pub async fn get_app_metadata_route_entry( // Push /route back let _ = page.push(PageSegment::PageType(PageType::Route)); + println!("get_app_route_entry:page: {:?}", page.to_string()); get_app_route_entry( nodejs_context, edge_context, - get_app_metadata_route_source(page.clone(), mode, metadata), - page.clone(), + get_app_metadata_route_source(page.clone(), mode, metadata, is_multi_dynamic), + page, project_root, Some(segment_config), next_config, @@ -237,7 +242,8 @@ async fn dynamic_text_route_source(path: Vc) -> Result, - page: AppPage, + _page: AppPage, + is_multi_dynamic: bool, ) -> Result>> { let stem = path.file_stem().await?; let stem = stem.as_deref().unwrap_or_default(); @@ -245,7 +251,9 @@ async fn dynamic_site_map_route_source( let content_type = get_content_type(path).await?; let mut static_generation_code = ""; - if mode.is_production() && page.contains(&PageSegment::Dynamic("__metadata_id__".into())) { + // if mode.is_production() && + // page.contains(&PageSegment::Dynamic("__metadata_id__".into())) { + if mode.is_production() && is_multi_dynamic { static_generation_code = indoc! { r#" export async function generateStaticParams() { @@ -261,6 +269,12 @@ async fn dynamic_site_map_route_source( }; } + let file_name = if is_multi_dynamic { + // append /[__metadata_id__] to the file path after stem + format!("{}/[__metadata_id__]", stem) + } else { + stem.to_string() + }; let code = formatdoc! { r#" import {{ NextResponse }} from 'next/server' diff --git a/packages/next/src/server/dev/turbopack-utils.ts b/packages/next/src/server/dev/turbopack-utils.ts index c1fcea30750e6..88fb8bcade45a 100644 --- a/packages/next/src/server/dev/turbopack-utils.ts +++ b/packages/next/src/server/dev/turbopack-utils.ts @@ -520,7 +520,9 @@ export async function handleRouteType({ const type = writtenEndpoint?.type - await manifestLoader.loadAppPathsManifest(page) + await manifestLoader.loadAppPathsManifest( + page.replace('/[__metadata_id__]', '') + ) if (type === 'edge') { await manifestLoader.loadMiddlewareManifest(page, 'app') } else {