diff --git a/crates/next-core/js/src/entry/server-renderer.tsx b/crates/next-core/js/src/entry/server-renderer.tsx index 8498c53213634..4842c7669e15e 100644 --- a/crates/next-core/js/src/entry/server-renderer.tsx +++ b/crates/next-core/js/src/entry/server-renderer.tsx @@ -130,6 +130,9 @@ async function runOperation( }, }; + if ("getStaticPaths" in otherExports) { + renderOpts.getStaticPaths = otherExports.getStaticPaths; + } if ("getStaticProps" in otherExports) { renderOpts.getStaticProps = otherExports.getStaticProps; } diff --git a/crates/next-core/src/app_source.rs b/crates/next-core/src/app_source.rs index 8e175506034bc..2d97ba3a6a264 100644 --- a/crates/next-core/src/app_source.rs +++ b/crates/next-core/src/app_source.rs @@ -3,7 +3,7 @@ use std::{ io::Write, }; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; use turbo_tasks::{ primitives::{StringVc, StringsVc}, TryJoinIterExt, Value, ValueToString, @@ -66,7 +66,7 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - util::regular_expression_for_path, + util::{pathname_for_path, regular_expression_for_path}, }; #[turbo_tasks::function] @@ -315,12 +315,12 @@ async fn create_app_source_for_directory( let layout = files.get("layout"); + // If a page exists but no layout exists, create a basic root layout + // in `app/layout.js` or `app/layout.tsx`. + // // TODO: Use let Some(page_file) = page in expression below when // https://rust-lang.github.io/rfcs/2497-if-let-chains.html lands - if page.is_some() && layout.is_none() && target == server_root { - // If a page exists but no layout exists, create a basic root layout - // in `app/layout.js` or `app/layout.tsx`. - let page_file = page.context("page must not be none")?; + if let (Some(page_file), None, true) = (page, layout, target == server_root) { // Use the extension to determine if the page file is TypeScript. // TODO: Use the presence of a tsconfig.json instead, like Next.js // stable does. @@ -358,10 +358,14 @@ async fn create_app_source_for_directory( list.push(LayoutSegment { files, target }.cell()); layouts = LayoutSegmentsVc::cell(list); if let Some(page_path) = page { + let pathname = pathname_for_path(server_root, target, false); + let path_regex = regular_expression_for_path(server_root, target, false); + sources.push(create_node_rendered_source( specificity, server_root, - regular_expression_for_path(server_root, target, false), + pathname, + path_regex, AppRenderer { context_ssr, context, diff --git a/crates/next-core/src/server_rendered_source.rs b/crates/next-core/src/server_rendered_source.rs index fcdc62fd49ae1..c0dd11ae6e112 100644 --- a/crates/next-core/src/server_rendered_source.rs +++ b/crates/next-core/src/server_rendered_source.rs @@ -51,7 +51,7 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - util::regular_expression_for_path, + util::{pathname_for_path, regular_expression_for_path}, }; /// Create a content source serving the `pages` or `src/pages` directory as @@ -166,11 +166,14 @@ async fn create_server_rendered_source_for_file( ) .build(); + let pathname = pathname_for_path(server_root, server_path, true); + let path_regex = regular_expression_for_path(server_root, server_path, true); + Ok(if *is_api_path.await? { create_node_api_source( specificity, server_root, - regular_expression_for_path(server_root, server_path, true), + path_regex, SsrEntry { context, entry_asset, @@ -186,7 +189,8 @@ async fn create_server_rendered_source_for_file( create_node_rendered_source( specificity, server_root, - regular_expression_for_path(server_root, server_path, true), + pathname, + path_regex, SsrEntry { context, entry_asset, diff --git a/crates/next-core/src/util.rs b/crates/next-core/src/util.rs index 2496147979aa2..3771ae455223f 100644 --- a/crates/next-core/src/util.rs +++ b/crates/next-core/src/util.rs @@ -1,16 +1,15 @@ use anyhow::{anyhow, bail, Result}; -use turbo_tasks::ValueToString; +use turbo_tasks::{primitives::StringVc, ValueToString}; use turbo_tasks_fs::FileSystemPathVc; use turbopack_node::path_regex::{PathRegexBuilder, PathRegexVc}; -/// Converts a filename within the server root to a regular expression with -/// named capture groups for every dynamic segment. +/// Converts a filename within the server root into a next pathname. #[turbo_tasks::function] -pub async fn regular_expression_for_path( +pub async fn pathname_for_path( server_root: FileSystemPathVc, server_path: FileSystemPathVc, has_extension: bool, -) -> Result { +) -> Result { let server_path_value = &*server_path.await?; let path = if let Some(path) = server_root.await?.get_path_to(server_path_value) { path @@ -33,6 +32,20 @@ pub async fn regular_expression_for_path( } else { path.strip_suffix("/index").unwrap_or(path) }; + + Ok(StringVc::cell(path.to_string())) +} + +/// Converts a filename within the server root into a regular expression with +/// named capture groups for every dynamic segment. +#[turbo_tasks::function] +pub async fn regular_expression_for_path( + server_root: FileSystemPathVc, + server_path: FileSystemPathVc, + has_extension: bool, +) -> Result { + let path = pathname_for_path(server_root, server_path, has_extension).await?; + let mut path_regex = PathRegexBuilder::new(); for segment in path.split('/') { if let Some(segment) = segment.strip_prefix('[') { diff --git a/crates/turbopack-node/src/node_rendered_source.rs b/crates/turbopack-node/src/node_rendered_source.rs index fa248e116cb1b..ab6137d236a90 100644 --- a/crates/turbopack-node/src/node_rendered_source.rs +++ b/crates/turbopack-node/src/node_rendered_source.rs @@ -38,6 +38,7 @@ use crate::path_regex::PathRegexVc; pub fn create_node_rendered_source( specificity: SpecificityVc, server_root: FileSystemPathVc, + pathname: StringVc, path_regex: PathRegexVc, entry: NodeEntryVc, runtime_entries: EcmascriptChunkPlaceablesVc, @@ -46,6 +47,7 @@ pub fn create_node_rendered_source( let source = NodeRenderContentSource { specificity, server_root, + pathname, path_regex, entry, runtime_entries, @@ -68,6 +70,7 @@ pub fn create_node_rendered_source( struct NodeRenderContentSource { specificity: SpecificityVc, server_root: FileSystemPathVc, + pathname: StringVc, path_regex: PathRegexVc, entry: NodeEntryVc, runtime_entries: EcmascriptChunkPlaceablesVc, @@ -176,7 +179,7 @@ impl ContentSource for NodeRenderContentSource { .headers .clone() .ok_or_else(|| anyhow!("headers needs to be provided"))?, - path: format!("/{path}"), + path: format!("/{}", this.pathname.await?), } .cell(), );