Skip to content

Commit

Permalink
Turbopack: Fix 500 handling in edge with pages router
Browse files Browse the repository at this point in the history
  • Loading branch information
timneutkens committed Feb 18, 2025
1 parent a7511f5 commit 9e5c689
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 35 deletions.
3 changes: 2 additions & 1 deletion crates/next-api/src/pages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ impl PagesProject {
app: _,
document: _,
error: _,
error_500: _,
} = &*pages_structure.await?;
let mut routes = FxIndexMap::default();

Expand Down Expand Up @@ -711,7 +712,7 @@ impl PageEndpoint {

#[turbo_tasks::function]
fn source(&self) -> Vc<Box<dyn Source>> {
Vc::upcast(FileSource::new(self.page.project_path()))
Vc::upcast(FileSource::new(self.page.file_path()))
}

#[turbo_tasks::function]
Expand Down
30 changes: 22 additions & 8 deletions crates/next-core/src/next_pages/page_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,13 @@ pub async fn create_page_ssr_entry_module(
INNER.into() => ssr_module,
};

let pages_structure_ref = pages_structure.await?;

if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page) {
inner_assets.insert(
INNER_DOCUMENT.into(),
process_global_item(
pages_structure.document(),
*pages_structure_ref.document,
Value::new(reference_type.clone()),
ssr_module_context,
)
Expand All @@ -130,7 +132,7 @@ pub async fn create_page_ssr_entry_module(
inner_assets.insert(
INNER_APP.into(),
process_global_item(
pages_structure.app(),
*pages_structure_ref.app,
Value::new(reference_type.clone()),
ssr_module_context,
)
Expand Down Expand Up @@ -177,7 +179,7 @@ fn process_global_item(
reference_type: Value<ReferenceType>,
module_context: Vc<Box<dyn AssetContext>>,
) -> Vc<Box<dyn Module>> {
let source = Vc::upcast(FileSource::new(item.project_path()));
let source = Vc::upcast(FileSource::new(item.file_path()));
module_context.process(source, reference_type).module()
}

Expand All @@ -197,6 +199,7 @@ async fn wrap_edge_page(
const INNER_DOCUMENT: &str = "INNER_DOCUMENT";
const INNER_APP: &str = "INNER_APP";
const INNER_ERROR: &str = "INNER_ERROR";
const INNER_ERROR_500: &str = "INNER_500";

let next_config_val = &*next_config.await?;

Expand Down Expand Up @@ -235,30 +238,41 @@ async fn wrap_edge_page(
fxindexmap! {
// TODO
"incrementalCacheHandler" => None,
"userland500Page" => None,
"userland500Page" => pages_structure.await?.error_500.map(|_| INNER_ERROR_500.into()),
},
)
.await?;

let inner_assets = fxindexmap! {
let pages_structure_ref = pages_structure.await?;

let mut inner_assets = fxindexmap! {
INNER.into() => entry,
INNER_DOCUMENT.into() => process_global_item(
pages_structure.document(),
*pages_structure_ref.document,
reference_type.clone(),
asset_context,
).to_resolved().await?,
INNER_APP.into() => process_global_item(
pages_structure.app(),
*pages_structure_ref.app,
reference_type.clone(),
asset_context,
).to_resolved().await?,
INNER_ERROR.into() => process_global_item(
pages_structure.error(),
*pages_structure_ref.error,
reference_type.clone(),
asset_context,
).to_resolved().await?,
};

if let Some(error_500) = pages_structure_ref.error_500 {
inner_assets.insert(
INNER_ERROR_500.into(),
process_global_item(*error_500, reference_type.clone(), asset_context)
.to_resolved()
.await?,
);
}

let wrapped = asset_context
.process(
Vc::upcast(source),
Expand Down
53 changes: 30 additions & 23 deletions crates/next-core/src/pages_structure.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use tracing::Instrument;
use turbo_rcstr::RcStr;
use turbo_tasks::{ResolvedVc, TryJoinIterExt, ValueToString, Vc};
use turbo_tasks::{OptionVcExt, ResolvedVc, TryJoinIterExt, ValueToString, Vc};
use turbo_tasks_fs::{
DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPath, FileSystemPathOption,
};
Expand Down Expand Up @@ -45,17 +45,22 @@ impl PagesStructureItem {
}

#[turbo_tasks::function]
pub async fn project_path(&self) -> Result<Vc<FileSystemPath>> {
pub async fn file_path(&self) -> Result<Vc<FileSystemPath>> {
// Check if the file path + extension exists in the filesystem, if so use that. If not fall
// back to the base path.
for ext in self.extensions.await?.into_iter() {
let project_path = self.base_path.append(format!(".{ext}").into());
let ty = *project_path.get_type().await?;
let file_path: Vc<FileSystemPath> = self.base_path.append(format!(".{ext}").into());
let ty = *file_path.get_type().await?;
if matches!(ty, FileSystemEntryType::File | FileSystemEntryType::Symlink) {
return Ok(project_path);
return Ok(file_path);
}
}
if let Some(fallback_path) = self.fallback_path {
Ok(*fallback_path)
} else {
// If the file path that was passed in already has an extension, for example
// `pages/index.js` it won't match the extensions list above because it already had an
// extension and for example `.js.js` obviously won't match
Ok(*self.base_path)
}
}
Expand All @@ -68,28 +73,11 @@ pub struct PagesStructure {
pub app: ResolvedVc<PagesStructureItem>,
pub document: ResolvedVc<PagesStructureItem>,
pub error: ResolvedVc<PagesStructureItem>,
pub error_500: Option<ResolvedVc<PagesStructureItem>>,
pub api: Option<ResolvedVc<PagesDirectoryStructure>>,
pub pages: Option<ResolvedVc<PagesDirectoryStructure>>,
}

#[turbo_tasks::value_impl]
impl PagesStructure {
#[turbo_tasks::function]
pub fn app(&self) -> Vc<PagesStructureItem> {
*self.app
}

#[turbo_tasks::function]
pub fn document(&self) -> Vc<PagesStructureItem> {
*self.document
}

#[turbo_tasks::function]
pub fn error(&self) -> Vc<PagesStructureItem> {
*self.error
}
}

#[turbo_tasks::value]
pub struct PagesDirectoryStructure {
pub project_path: ResolvedVc<FileSystemPath>,
Expand Down Expand Up @@ -157,6 +145,7 @@ async fn get_pages_structure_for_root_directory(
let page_extensions_raw = &*page_extensions.await?;

let mut api_directory = None;
let mut error_500_item = None;

let project_path = project_path.await?;
let pages_directory = if let Some(project_path) = &*project_path {
Expand All @@ -179,6 +168,23 @@ async fn get_pages_structure_for_root_directory(
let base_path = project_path.join(basename.into());
match basename {
"_app" | "_document" | "_error" => {}
"500" => {
let item_next_router_path =
next_router_path_for_basename(next_router_path, basename);
let item_original_path = next_router_path.join(basename.into());
let item = PagesStructureItem::new(
base_path,
page_extensions,
None,
item_next_router_path,
item_original_path,
);

error_500_item = Some(item);

items.push((basename, item));
}

basename => {
let item_next_router_path =
next_router_path_for_basename(next_router_path, basename);
Expand Down Expand Up @@ -294,6 +300,7 @@ async fn get_pages_structure_for_root_directory(
app: app_item.to_resolved().await?,
document: document_item.to_resolved().await?,
error: error_item.to_resolved().await?,
error_500: error_500_item.to_resolved().await?,
api: api_directory,
pages: pages_directory,
}
Expand Down
5 changes: 2 additions & 3 deletions test/turbopack-build-tests-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14317,11 +14317,10 @@
"streaming dev dev should not stream to crawlers or google pagerender bot",
"streaming dev dev should render 500 error correctly",
"streaming dev dev should render fallback if error raised from suspense during streaming",
"streaming dev dev should support streaming for fizz response"
],
"failed": [
"streaming dev dev should support streaming for fizz response",
"production mode streaming prod prod should render 500 error correctly"
],
"failed": [],
"pending": [],
"flakey": [],
"runtimeError": false
Expand Down

0 comments on commit 9e5c689

Please sign in to comment.