Skip to content

Commit

Permalink
chore: add structured app page path type
Browse files Browse the repository at this point in the history
  • Loading branch information
ForsakenHarmony committed Sep 7, 2023
1 parent 9bb9f07 commit 3250d96
Show file tree
Hide file tree
Showing 9 changed files with 488 additions and 300 deletions.
34 changes: 10 additions & 24 deletions packages/next-swc/crates/next-api/src/app.rs
Expand Up @@ -8,7 +8,7 @@ use next_core::{
mode::NextMode,
next_app::{
get_app_client_references_chunks, get_app_client_shared_chunks, get_app_page_entry,
get_app_route_entry, AppEntry,
get_app_route_entry, AppEntry, AppPage,
},
next_client::{
get_client_module_options_context, get_client_resolve_options_context,
Expand Down Expand Up @@ -344,8 +344,7 @@ impl AppProject {
.map(|(pathname, app_entrypoint)| async {
Ok((
pathname.clone(),
*app_entry_point_to_route(self, app_entrypoint.clone(), pathname.clone())
.await?,
*app_entry_point_to_route(self, app_entrypoint.clone()).await?,
))
})
.try_join()
Expand All @@ -360,22 +359,17 @@ impl AppProject {
pub async fn app_entry_point_to_route(
app_project: Vc<AppProject>,
entrypoint: AppEntrypoint,
pathname: String,
) -> Vc<Route> {
match entrypoint {
AppEntrypoint::AppPage {
original_name,
loader_tree,
} => Route::AppPage {
AppEntrypoint::AppPage { page, loader_tree } => Route::AppPage {
html_endpoint: Vc::upcast(
AppEndpoint {
ty: AppEndpointType::Page {
ty: AppPageEndpointType::Html,
loader_tree,
},
app_project,
pathname: pathname.clone(),
original_name: original_name.clone(),
page: page.clone(),
}
.cell(),
),
Expand All @@ -386,22 +380,17 @@ pub async fn app_entry_point_to_route(
loader_tree,
},
app_project,
pathname,
original_name,
page,
}
.cell(),
),
},
AppEntrypoint::AppRoute {
original_name,
path,
} => Route::AppRoute {
AppEntrypoint::AppRoute { page, path } => Route::AppRoute {
endpoint: Vc::upcast(
AppEndpoint {
ty: AppEndpointType::Route { path },
app_project,
pathname,
original_name,
page,
}
.cell(),
),
Expand Down Expand Up @@ -431,8 +420,7 @@ enum AppEndpointType {
struct AppEndpoint {
ty: AppEndpointType,
app_project: Vc<AppProject>,
pathname: String,
original_name: String,
page: AppPage,
}

#[turbo_tasks::value_impl]
Expand All @@ -444,8 +432,7 @@ impl AppEndpoint {
self.app_project.edge_rsc_module_context(),
loader_tree,
self.app_project.app_dir(),
self.pathname.clone(),
self.original_name.clone(),
self.page.clone(),
self.app_project.project().project_path(),
)
}
Expand All @@ -456,8 +443,7 @@ impl AppEndpoint {
self.app_project.rsc_module_context(),
self.app_project.edge_rsc_module_context(),
Vc::upcast(FileSource::new(path)),
self.pathname.clone(),
self.original_name.clone(),
self.page.clone(),
self.app_project.project().project_path(),
)
}
Expand Down
18 changes: 5 additions & 13 deletions packages/next-swc/crates/next-build/src/next_app/app_entries.rs
Expand Up @@ -187,31 +187,23 @@ pub async fn get_app_entries(
let mut entries = entrypoints
.await?
.iter()
.map(|(pathname, entrypoint)| async move {
.map(|(_, entrypoint)| async move {
Ok(match entrypoint {
Entrypoint::AppPage {
original_name,
loader_tree,
} => get_app_page_entry(
Entrypoint::AppPage { page, loader_tree } => get_app_page_entry(
rsc_context,
// TODO add edge support
rsc_context,
*loader_tree,
app_dir,
pathname.clone(),
original_name.clone(),
page.clone(),
project_root,
),
Entrypoint::AppRoute {
original_name,
path,
} => get_app_route_entry(
Entrypoint::AppRoute { page, path } => get_app_route_entry(
rsc_context,
// TODO add edge support
rsc_context,
Vc::upcast(FileSource::new(*path)),
pathname.clone(),
original_name.clone(),
page.clone(),
project_root,
),
})
Expand Down
1 change: 1 addition & 0 deletions packages/next-swc/crates/next-core/Cargo.toml
Expand Up @@ -39,6 +39,7 @@ turbopack-binding = { workspace = true, features = [
"__turbo_tasks_hash",
"__turbopack",
"__turbopack_build",
"__turbopack_cli_utils",
"__turbopack_core",
"__turbopack_dev",
"__turbopack_dev_server",
Expand Down
78 changes: 37 additions & 41 deletions packages/next-swc/crates/next-core/src/app_source.rs
Expand Up @@ -65,7 +65,7 @@ use crate::{
fallback::get_fallback_page,
loader_tree::{LoaderTreeModule, ServerComponentTransition},
mode::NextMode,
next_app::UnsupportedDynamicMetadataIssue,
next_app::{AppPage, AppPath, PathSegment, UnsupportedDynamicMetadataIssue},
next_client::{
context::{
get_client_assets_path, get_client_module_options_context,
Expand Down Expand Up @@ -95,31 +95,28 @@ use crate::{
util::{render_data, NextRuntime},
};

fn pathname_to_segments(pathname: &str) -> Result<(Vec<BaseSegment>, RouteType)> {
fn app_path_to_segments(path: &AppPath) -> Result<(Vec<BaseSegment>, RouteType)> {
let mut segments = Vec::new();
let mut split = pathname.split('/');
while let Some(segment) = split.next() {
if segment.is_empty()
|| (segment.starts_with('(') && segment.ends_with(')') || segment.starts_with('@'))
{
// ignore
} else if segment.starts_with("[[...") && segment.ends_with("]]")
|| segment.starts_with("[...") && segment.ends_with(']')
{
// (optional) catch all segment
if split.remainder().is_some() {
bail!(
"Invalid route {}, catch all segment must be the last segment",
pathname
)
let mut iter = path.iter().peekable();

while let Some(segment) = iter.next() {
match segment {
PathSegment::Static(s) => {
segments.push(BaseSegment::Static(s.to_string()));
}
PathSegment::Dynamic(_) => {
segments.push(BaseSegment::Dynamic);
}
PathSegment::CatchAll(_) | PathSegment::OptionalCatchAll(_) => {
if iter.peek().is_some() {
bail!(
"Invalid route {}, catch all segment must be the last segment",
path
)
}

return Ok((segments, RouteType::CatchAll));
}
return Ok((segments, RouteType::CatchAll));
} else if segment.starts_with('[') || segment.ends_with(']') {
// dynamic segment
segments.push(BaseSegment::Dynamic);
} else {
// normal segment
segments.push(BaseSegment::Static(segment.to_string()));
}
}
Ok((segments, RouteType::Exact))
Expand Down Expand Up @@ -654,12 +651,12 @@ pub async fn create_app_source(
let entrypoints = entrypoints.await?;
let mut sources: Vec<_> = entrypoints
.iter()
.map(|(pathname, entrypoint)| match *entrypoint {
.map(|(_, entrypoint)| match *entrypoint {
Entrypoint::AppPage {
original_name: _,
ref page,
loader_tree,
} => create_app_page_source_for_route(
pathname.clone(),
page.clone(),
loader_tree,
context_ssr,
context,
Expand All @@ -672,11 +669,8 @@ pub async fn create_app_source(
output_path,
render_data,
),
Entrypoint::AppRoute {
original_name: _,
path,
} => create_app_route_source_for_route(
pathname.clone(),
Entrypoint::AppRoute { ref page, path } => create_app_route_source_for_route(
page.clone(),
path,
context_ssr,
project_path,
Expand All @@ -696,7 +690,7 @@ pub async fn create_app_source(
.collect();

if let Some(&Entrypoint::AppPage {
original_name: _,
page: _,
loader_tree,
}) = entrypoints.get("/_not-found")
{
Expand Down Expand Up @@ -769,7 +763,7 @@ async fn create_global_metadata_source(

#[turbo_tasks::function]
async fn create_app_page_source_for_route(
pathname: String,
page: AppPage,
loader_tree: Vc<LoaderTree>,
context_ssr: Vc<ModuleAssetContext>,
context: Vc<ModuleAssetContext>,
Expand All @@ -782,11 +776,12 @@ async fn create_app_page_source_for_route(
intermediate_output_path_root: Vc<FileSystemPath>,
render_data: Vc<JsonValue>,
) -> Result<Vc<Box<dyn ContentSource>>> {
let pathname_vc = Vc::cell(pathname.clone());
let app_path = AppPath::from(page.clone());
let pathname_vc = Vc::cell(app_path.to_string());

let params_matcher = NextParamsMatcher::new(pathname_vc);

let (base_segments, route_type) = pathname_to_segments(&pathname)?;
let (base_segments, route_type) = app_path_to_segments(&app_path)?;

let source = create_node_rendered_source(
project_path,
Expand Down Expand Up @@ -814,7 +809,7 @@ async fn create_app_page_source_for_route(
should_debug("app_source"),
);

Ok(source.issue_file_path(app_dir, format!("Next.js App Page Route {pathname}")))
Ok(source.issue_file_path(app_dir, format!("Next.js App Page Route {app_path}")))
}

#[turbo_tasks::function]
Expand Down Expand Up @@ -864,7 +859,7 @@ async fn create_app_not_found_page_source(

#[turbo_tasks::function]
async fn create_app_route_source_for_route(
pathname: String,
page: AppPage,
entry_path: Vc<FileSystemPath>,
context_ssr: Vc<ModuleAssetContext>,
project_path: Vc<FileSystemPath>,
Expand All @@ -875,11 +870,12 @@ async fn create_app_route_source_for_route(
intermediate_output_path_root: Vc<FileSystemPath>,
render_data: Vc<JsonValue>,
) -> Result<Vc<Box<dyn ContentSource>>> {
let pathname_vc = Vc::cell(pathname.to_string());
let app_path = AppPath::from(page.clone());
let pathname_vc = Vc::cell(app_path.to_string());

let params_matcher = NextParamsMatcher::new(pathname_vc);

let (base_segments, route_type) = pathname_to_segments(&pathname)?;
let (base_segments, route_type) = app_path_to_segments(&app_path)?;

let source = create_node_api_source(
project_path,
Expand All @@ -906,7 +902,7 @@ async fn create_app_route_source_for_route(
should_debug("app_source"),
);

Ok(source.issue_file_path(app_dir, format!("Next.js App Route {pathname}")))
Ok(source.issue_file_path(app_dir, format!("Next.js App Route {app_path}")))
}

/// The renderer for pages in app directory
Expand Down

0 comments on commit 3250d96

Please sign in to comment.