Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion .github/labeler.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,35 @@
"examples": ["examples/**"],
"Font (next/font)": ["**/*font*"],
"tests": ["test/**", "bench/**"],
"Turbopack": ["crates/next-*/**"],
"Turbopack": ["crates/next-*/**", "crates/napi/**", "turbopack/**"],
"Rspack": [
{ "type": "user", "pattern": "9aoy" },
{ "type": "user", "pattern": "ahabhgk" },
{ "type": "user", "pattern": "bvanjoi" },
{ "type": "user", "pattern": "chenjiahan" },
{ "type": "user", "pattern": "CPunisher" },
{ "type": "user", "pattern": "easy1090" },
{ "type": "user", "pattern": "fi3ework" },
{ "type": "user", "pattern": "GiveMe-A-Name" },
{ "type": "user", "pattern": "h-a-n-a" },
{ "type": "user", "pattern": "hardfist" },
{ "type": "user", "pattern": "inottn" },
{ "type": "user", "pattern": "jerrykingxyz" },
{ "type": "user", "pattern": "JSerFeng" },
{ "type": "user", "pattern": "lingyucoder" },
{ "type": "user", "pattern": "nyqykk" },
{ "type": "user", "pattern": "sanyuan0704" },
{ "type": "user", "pattern": "ScriptedAlchemy" },
{ "type": "user", "pattern": "SoonIter" },
{ "type": "user", "pattern": "stormslowly" },
{ "type": "user", "pattern": "SyMind" },
{ "type": "user", "pattern": "Timeless0911" },
{ "type": "user", "pattern": "valorkin" },
{ "type": "user", "pattern": "xc2" },
{ "type": "user", "pattern": "zackarychapple" },
{ "type": "user", "pattern": "zoolsher" },
"packages/next/src/build/**"
],
"created-by: Chrome Aurora": [
{ "type": "user", "pattern": "atcastle" },
{ "type": "user", "pattern": "devknoll" },
Expand Down
7 changes: 6 additions & 1 deletion crates/next-api/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,12 @@ impl AppProject {

#[turbo_tasks::function]
fn app_entrypoints(&self) -> Vc<AppEntrypoints> {
get_entrypoints(*self.app_dir, self.project.next_config().page_extensions())
let conf = self.project.next_config();
get_entrypoints(
*self.app_dir,
conf.page_extensions(),
conf.is_global_not_found_enabled(),
)
}

#[turbo_tasks::function]
Expand Down
16 changes: 16 additions & 0 deletions crates/next-core/src/app_page_loader_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ impl AppPageLoaderTreeBuilder {
default,
error,
global_error,
global_not_found,
layout,
loading,
template,
Expand Down Expand Up @@ -375,6 +376,8 @@ impl AppPageLoaderTreeBuilder {
.await?;
self.write_modules_entry(AppDirModuleType::GlobalError, *global_error)
.await?;
self.write_modules_entry(AppDirModuleType::GlobalNotFound, *global_not_found)
.await?;

let modules_code = replace(&mut self.loader_tree_code, temp_loader_tree_code);

Expand All @@ -399,6 +402,7 @@ impl AppPageLoaderTreeBuilder {
let loader_tree = &*loader_tree.await?;

let modules = &loader_tree.modules;
// load global-error module
if let Some(global_error) = modules.global_error {
let module = self
.base
Expand All @@ -407,6 +411,17 @@ impl AppPageLoaderTreeBuilder {
.await?;
self.base.inner_assets.insert(GLOBAL_ERROR.into(), module);
};
// load global-not-found module
if let Some(global_not_found) = modules.global_not_found {
let module = self
.base
.process_source(Vc::upcast(FileSource::new(*global_not_found)))
.to_resolved()
.await?;
self.base
.inner_assets
.insert(GLOBAL_NOT_FOUND.into(), module);
};

self.walk_tree(loader_tree, true).await?;
Ok(AppPageLoaderTreeModule {
Expand Down Expand Up @@ -439,3 +454,4 @@ impl AppPageLoaderTreeModule {
}

pub const GLOBAL_ERROR: &str = "GLOBAL_ERROR_MODULE";
pub const GLOBAL_NOT_FOUND: &str = "GLOBAL_NOT_FOUND_MODULE";
71 changes: 60 additions & 11 deletions crates/next-core/src/app_structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ pub struct AppDirModules {
#[serde(skip_serializing_if = "Option::is_none")]
pub global_error: Option<ResolvedVc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub global_not_found: Option<ResolvedVc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub loading: Option<ResolvedVc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template: Option<ResolvedVc<FileSystemPath>>,
Expand All @@ -63,6 +65,7 @@ impl AppDirModules {
layout: self.layout,
error: self.error,
global_error: self.global_error,
global_not_found: self.global_not_found,
loading: self.loading,
template: self.template,
not_found: self.not_found,
Expand Down Expand Up @@ -322,6 +325,7 @@ async fn get_directory_tree_internal(
"layout" => modules.layout = Some(file),
"error" => modules.error = Some(file),
"global-error" => modules.global_error = Some(file),
"global-not-found" => modules.global_not_found = Some(file),
"loading" => modules.loading = Some(file),
"template" => modules.template = Some(file),
"forbidden" => modules.forbidden = Some(file),
Expand Down Expand Up @@ -730,11 +734,13 @@ fn add_app_metadata_route(
pub fn get_entrypoints(
app_dir: Vc<FileSystemPath>,
page_extensions: Vc<Vec<RcStr>>,
is_global_not_found_enabled: Vc<bool>,
) -> Vc<Entrypoints> {
directory_tree_to_entrypoints(
app_dir,
get_directory_tree(app_dir, page_extensions),
get_global_metadata(app_dir, page_extensions),
is_global_not_found_enabled,
Default::default(),
)
}
Expand All @@ -744,11 +750,13 @@ fn directory_tree_to_entrypoints(
app_dir: Vc<FileSystemPath>,
directory_tree: Vc<DirectoryTree>,
global_metadata: Vc<GlobalMetadata>,
is_global_not_found_enabled: Vc<bool>,
root_layouts: Vc<FileSystemPathVec>,
) -> Vc<Entrypoints> {
directory_tree_to_entrypoints_internal(
app_dir,
global_metadata,
is_global_not_found_enabled,
"".into(),
directory_tree,
AppPage::new(),
Expand Down Expand Up @@ -1124,6 +1132,7 @@ async fn default_route_tree(
async fn directory_tree_to_entrypoints_internal(
app_dir: ResolvedVc<FileSystemPath>,
global_metadata: Vc<GlobalMetadata>,
is_global_not_found_enabled: Vc<bool>,
directory_name: RcStr,
directory_tree: Vc<DirectoryTree>,
app_page: AppPage,
Expand All @@ -1133,6 +1142,7 @@ async fn directory_tree_to_entrypoints_internal(
directory_tree_to_entrypoints_internal_untraced(
app_dir,
global_metadata,
is_global_not_found_enabled,
directory_name,
directory_tree,
app_page,
Expand All @@ -1145,6 +1155,7 @@ async fn directory_tree_to_entrypoints_internal(
async fn directory_tree_to_entrypoints_internal_untraced(
app_dir: ResolvedVc<FileSystemPath>,
global_metadata: Vc<GlobalMetadata>,
is_global_not_found_enabled: Vc<bool>,
directory_name: RcStr,
directory_tree: Vc<DirectoryTree>,
app_page: AppPage,
Expand Down Expand Up @@ -1284,6 +1295,13 @@ async fn directory_tree_to_entrypoints_internal_untraced(

// Next.js has this logic in "collect-app-paths", where the root not-found page
// is considered as its own entry point.

// Determine if we enable the global not-found feature.
let is_global_not_found_enabled = *is_global_not_found_enabled.await?;
let use_global_not_found =
is_global_not_found_enabled || modules.global_not_found.is_some();

let not_found_root_modules = modules.without_leafs();
let not_found_tree = AppPageLoaderTree {
page: app_page.clone(),
segment: directory_name.clone(),
Expand All @@ -1296,24 +1314,54 @@ async fn directory_tree_to_entrypoints_internal_untraced(
page: app_page.clone(),
segment: "__PAGE__".into(),
parallel_routes: FxIndexMap::default(),
modules: AppDirModules {
page: match modules.not_found {
Some(v) => Some(v),
None => Some(get_next_package(*app_dir)
.join("dist/client/components/not-found-error.js".into())
.to_resolved()
.await?),
},
..Default::default()
modules: if use_global_not_found {
// if global-not-found.js is present:
// we use it for the page and no layout, since layout is included in global-not-found.js;
AppDirModules {
layout: None,
page: match modules.global_not_found {
Some(v) => Some(v),
None => Some(get_next_package(*app_dir)
.join("dist/client/components/global-not-found.js".into())
.to_resolved()
.await?),
},
..Default::default()
}
} else {
// if global-not-found.js is not present:
// we search if we can compose root layout with the root not-found.js;
AppDirModules {
page: match modules.not_found {
Some(v) => Some(v),
None => Some(get_next_package(*app_dir)
.join("dist/client/components/not-found-error.js".into())
.to_resolved()
.await?),
},
..Default::default()
}
},
global_metadata: global_metadata.to_resolved().await?,
}
},
modules: AppDirModules::default(),
modules: AppDirModules {
..Default::default()
},
global_metadata: global_metadata.to_resolved().await?,
},
},
modules: modules.without_leafs(),
modules: AppDirModules {
// `global-not-found.js` does not need a layout since it's included.
// Skip it if it's present.
// Otherwise, we need to compose it with the root layout to compose with not-found.js boundary.
layout: if use_global_not_found {
None
} else {
modules.layout
},
..not_found_root_modules
},
global_metadata: global_metadata.to_resolved().await?,
}
.resolved_cell();
Expand Down Expand Up @@ -1345,6 +1393,7 @@ async fn directory_tree_to_entrypoints_internal_untraced(
let map = directory_tree_to_entrypoints_internal(
*app_dir,
global_metadata,
is_global_not_found_enabled,
subdir_name.clone(),
*subdirectory,
child_app_page.clone(),
Expand Down
2 changes: 2 additions & 0 deletions crates/next-core/src/base_loader_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub enum AppDirModuleType {
Forbidden,
Unauthorized,
GlobalError,
GlobalNotFound,
}

impl AppDirModuleType {
Expand All @@ -47,6 +48,7 @@ impl AppDirModuleType {
AppDirModuleType::Forbidden => "forbidden",
AppDirModuleType::Unauthorized => "unauthorized",
AppDirModuleType::GlobalError => "global-error",
AppDirModuleType::GlobalNotFound => "global-not-found",
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions crates/next-core/src/next_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,8 @@ pub struct ExperimentalConfig {
turbopack_persistent_caching: Option<bool>,
turbopack_source_maps: Option<bool>,
turbopack_tree_shaking: Option<bool>,
// Whether to enable the global-not-found convention
global_not_found: Option<bool>,
}

#[derive(
Expand Down Expand Up @@ -1189,6 +1191,11 @@ impl NextConfig {
Vc::cell(self.page_extensions.clone())
}

#[turbo_tasks::function]
pub fn is_global_not_found_enabled(&self) -> Vc<bool> {
Vc::cell(self.experimental.global_not_found.unwrap_or_default())
}

#[turbo_tasks::function]
pub fn transpile_packages(&self) -> Vc<Vec<RcStr>> {
Vc::cell(self.transpile_packages.clone().unwrap_or_default())
Expand Down
2 changes: 1 addition & 1 deletion crates/next-core/src/next_font/font_fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl FontFallback {
}

#[turbo_tasks::value(transparent)]
pub(crate) struct FontFallbacks(Vec<ResolvedVc<FontFallback>>);
pub(crate) struct FontFallbacks(pub Vec<ResolvedVc<FontFallback>>);

#[turbo_tasks::value_impl]
impl FontFallbacks {
Expand Down
21 changes: 16 additions & 5 deletions crates/next-core/src/next_font/local/errors.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
use thiserror::Error;
use std::fmt::Display;

use serde::{Deserialize, Serialize};
use turbo_rcstr::RcStr;
use turbo_tasks::{trace::TraceRawVcs, NonLocalValue};

pub(crate) enum FontResult<T> {
Ok(T),
FontFileNotFound(FontFileNotFound),
}

#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, NonLocalValue, TraceRawVcs)]
pub(crate) struct FontFileNotFound(pub RcStr);

#[derive(Debug, Error)]
pub enum FontError {
#[error("could not find font file")]
FontFileNotFound(RcStr),
impl Display for FontFileNotFound {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Font file not found: Can't resolve {}'", self.0)
}
}
Loading
Loading