Skip to content

Commit

Permalink
fix renaming of page files, add handling of symlinked pages (#68195)
Browse files Browse the repository at this point in the history
### What?

When renaming a page from `page.js` to `page.tsx` it can temporarily
have both variants which end up writing the same files.

Also fixes symlinked page files

Depends on vercel/turborepo#8851

fixes PACK-2718
  • Loading branch information
sokra authored and ForsakenHarmony committed Aug 14, 2024
1 parent e783b3c commit 35798bf
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 73 deletions.
31 changes: 15 additions & 16 deletions crates/next-api/src/pages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,25 +104,25 @@ impl PagesProject {
async fn add_page_to_routes(
routes: &mut IndexMap<RcStr, Route>,
page: Vc<PagesStructureItem>,
make_route: impl Fn(Vc<RcStr>, Vc<RcStr>, Vc<FileSystemPath>) -> Route,
make_route: impl Fn(Vc<RcStr>, Vc<RcStr>, Vc<PagesStructureItem>) -> Route,
) -> Result<()> {
let PagesStructureItem {
next_router_path,
project_path,
original_path,
..
} = *page.await?;
let pathname: RcStr = format!("/{}", next_router_path.await?.path).into();
let pathname_vc = Vc::cell(pathname.clone());
let original_name = Vc::cell(format!("/{}", original_path.await?.path).into());
let route = make_route(pathname_vc, original_name, project_path);
let route = make_route(pathname_vc, original_name, page);
routes.insert(pathname, route);
Ok(())
}

async fn add_dir_to_routes(
routes: &mut IndexMap<RcStr, Route>,
dir: Vc<PagesDirectoryStructure>,
make_route: impl Fn(Vc<RcStr>, Vc<RcStr>, Vc<FileSystemPath>) -> Route,
make_route: impl Fn(Vc<RcStr>, Vc<RcStr>, Vc<PagesStructureItem>) -> Route,
) -> Result<()> {
let mut queue = vec![dir];
while let Some(dir) = queue.pop() {
Expand All @@ -143,36 +143,36 @@ impl PagesProject {
}

if let Some(api) = api {
add_dir_to_routes(&mut routes, *api, |pathname, original_name, path| {
add_dir_to_routes(&mut routes, *api, |pathname, original_name, page| {
Route::PageApi {
endpoint: Vc::upcast(PageEndpoint::new(
PageEndpointType::Api,
self,
pathname,
original_name,
path,
page,
pages_structure,
)),
}
})
.await?;
}

let make_page_route = |pathname, original_name, path| Route::Page {
let make_page_route = |pathname, original_name, page| Route::Page {
html_endpoint: Vc::upcast(PageEndpoint::new(
PageEndpointType::Html,
self,
pathname,
original_name,
path,
page,
pages_structure,
)),
data_endpoint: Vc::upcast(PageEndpoint::new(
PageEndpointType::Data,
self,
pathname,
original_name,
path,
page,
pages_structure,
)),
};
Expand All @@ -196,19 +196,18 @@ impl PagesProject {
) -> Result<Vc<Box<dyn Endpoint>>> {
let PagesStructureItem {
next_router_path,
project_path,
original_path,
..
} = *item.await?;
let pathname: RcStr = format!("/{}", next_router_path.await?.path).into();
let pathname_vc = Vc::cell(pathname.clone());
let original_name = Vc::cell(format!("/{}", original_path.await?.path).into());
let path = project_path;
let endpoint = Vc::upcast(PageEndpoint::new(
ty,
self,
pathname_vc,
original_name,
path,
item,
self.pages_structure(),
));
Ok(endpoint)
Expand Down Expand Up @@ -570,7 +569,7 @@ struct PageEndpoint {
pages_project: Vc<PagesProject>,
pathname: Vc<RcStr>,
original_name: Vc<RcStr>,
path: Vc<FileSystemPath>,
page: Vc<PagesStructureItem>,
pages_structure: Vc<PagesStructure>,
}

Expand Down Expand Up @@ -601,15 +600,15 @@ impl PageEndpoint {
pages_project: Vc<PagesProject>,
pathname: Vc<RcStr>,
original_name: Vc<RcStr>,
path: Vc<FileSystemPath>,
page: Vc<PagesStructureItem>,
pages_structure: Vc<PagesStructure>,
) -> Vc<Self> {
PageEndpoint {
ty,
pages_project,
pathname,
original_name,
path,
page,
pages_structure,
}
.cell()
Expand All @@ -618,7 +617,7 @@ impl PageEndpoint {
#[turbo_tasks::function]
async fn source(self: Vc<Self>) -> Result<Vc<Box<dyn Source>>> {
let this = self.await?;
Ok(Vc::upcast(FileSource::new(this.path)))
Ok(Vc::upcast(FileSource::new(this.page.project_path())))
}

#[turbo_tasks::function]
Expand Down
3 changes: 2 additions & 1 deletion crates/next-core/src/app_structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ async fn get_directory_tree_internal(
let mut metadata_twitter = Vec::new();

for (basename, entry) in entries {
match *entry {
let entry = entry.resolve_symlink().await?;
match entry {
DirectoryEntry::File(file) => {
let file = file.resolve().await?;
// Do not process .d.ts files as routes
Expand Down
125 changes: 69 additions & 56 deletions crates/next-core/src/pages_structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use crate::next_import_map::get_next_package;
/// A final route in the pages directory.
#[turbo_tasks::value]
pub struct PagesStructureItem {
pub project_path: Vc<FileSystemPath>,
pub base_path: Vc<FileSystemPath>,
pub extensions: Vc<Vec<RcStr>>,
pub fallback_path: Option<Vc<FileSystemPath>>,

/// Pathname of this item in the Next.js router.
pub next_router_path: Vc<FileSystemPath>,
/// Unique path corresponding to this item. This differs from
Expand All @@ -25,18 +28,38 @@ pub struct PagesStructureItem {
impl PagesStructureItem {
#[turbo_tasks::function]
async fn new(
project_path: Vc<FileSystemPath>,
base_path: Vc<FileSystemPath>,
extensions: Vc<Vec<RcStr>>,
fallback_path: Option<Vc<FileSystemPath>>,
next_router_path: Vc<FileSystemPath>,
original_path: Vc<FileSystemPath>,
) -> Result<Vc<Self>> {
Ok(PagesStructureItem {
project_path,
base_path,
extensions,
fallback_path,
next_router_path,
original_path,
}
.cell())
}

#[turbo_tasks::function]
pub async fn project_path(&self) -> Result<Vc<FileSystemPath>> {
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?;
if matches!(ty, FileSystemEntryType::File | FileSystemEntryType::Symlink) {
return Ok(project_path);
}
}
if let Some(fallback_path) = self.fallback_path {
Ok(fallback_path)
} else {
Ok(self.base_path)
}
}

/// Returns a completion that changes when any route in the whole tree
/// changes.
#[turbo_tasks::function]
Expand All @@ -45,11 +68,6 @@ impl PagesStructureItem {
this.next_router_path.await?;
Ok(Completion::new())
}

#[turbo_tasks::function]
pub fn project_path(&self) -> Vc<FileSystemPath> {
self.project_path
}
}

/// A (sub)directory in the pages directory with all analyzed routes and
Expand Down Expand Up @@ -148,12 +166,20 @@ pub async fn find_pages_structure(
next_router_root: Vc<FileSystemPath>,
page_extensions: Vc<Vec<RcStr>>,
) -> Result<Vc<PagesStructure>> {
let pages_root = project_root.join("pages".into());
let pages_root = project_root
.join("pages".into())
.realpath()
.resolve()
.await?;
let pages_root = Vc::<FileSystemPathOption>::cell(
if *pages_root.get_type().await? == FileSystemEntryType::Directory {
Some(pages_root)
} else {
let src_pages_root = project_root.join("src/pages".into());
let src_pages_root = project_root
.join("src/pages".into())
.realpath()
.resolve()
.await?;
if *src_pages_root.get_type().await? == FileSystemEntryType::Directory {
Some(src_pages_root)
} else {
Expand Down Expand Up @@ -185,61 +211,39 @@ async fn get_pages_structure_for_root_directory(
) -> Result<Vc<PagesStructure>> {
let page_extensions_raw = &*page_extensions.await?;

let mut app_item = None;
let mut document_item = None;
let mut error_item = None;
let mut api_directory = None;

let pages_directory = if let Some(project_path) = &*project_path.await? {
let project_path = project_path.await?;
let pages_directory = if let Some(project_path) = &*project_path {
let mut children = vec![];
let mut items = vec![];

let dir_content = project_path.read_dir().await?;
if let DirectoryContent::Entries(entries) = &*dir_content {
for (name, entry) in entries.iter() {
let entry = entry.resolve_symlink().await?;
match entry {
DirectoryEntry::File(file_project_path) => {
DirectoryEntry::File(_) => {
// Do not process .d.ts files as routes
if name.ends_with(".d.ts") {
continue;
}
let Some(basename) = page_basename(name, page_extensions_raw) else {
continue;
};
let base_path = project_path.join(basename.into());
match basename {
"_app" => {
let item_next_router_path = next_router_path.join("_app".into());
app_item = Some(PagesStructureItem::new(
*file_project_path,
item_next_router_path,
item_next_router_path,
));
}
"_document" => {
let item_next_router_path =
next_router_path.join("_document".into());
document_item = Some(PagesStructureItem::new(
*file_project_path,
item_next_router_path,
item_next_router_path,
));
}
"_error" => {
let item_next_router_path = next_router_path.join("_error".into());
error_item = Some(PagesStructureItem::new(
*file_project_path,
item_next_router_path,
item_next_router_path,
));
}
"_app" | "_document" | "_error" => {}
basename => {
let item_next_router_path =
next_router_path_for_basename(next_router_path, basename);
let item_original_path = next_router_path.join(basename.into());
items.push((
basename,
PagesStructureItem::new(
*file_project_path,
base_path,
page_extensions,
None,
item_next_router_path,
item_original_path,
),
Expand All @@ -250,7 +254,7 @@ async fn get_pages_structure_for_root_directory(
DirectoryEntry::Directory(dir_project_path) => match name.as_str() {
"api" => {
api_directory = Some(get_pages_structure_for_directory(
*dir_project_path,
dir_project_path,
next_router_path.join(name.clone()),
1,
page_extensions,
Expand All @@ -260,7 +264,7 @@ async fn get_pages_structure_for_root_directory(
children.push((
name,
get_pages_structure_for_directory(
*dir_project_path,
dir_project_path,
next_router_path.join(name.clone()),
1,
page_extensions,
Expand Down Expand Up @@ -290,34 +294,40 @@ async fn get_pages_structure_for_root_directory(
None
};

let app_item = if let Some(app_item) = app_item {
app_item
let pages_path = if let Some(project_path) = *project_path {
project_path
} else {
project_root.join("pages".into())
};

let app_item = {
let app_router_path = next_router_path.join("_app".into());
PagesStructureItem::new(
get_next_package(project_root).join("app.js".into()),
pages_path.join("_app".into()),
page_extensions,
Some(get_next_package(project_root).join("app.js".into())),
app_router_path,
app_router_path,
)
};

let document_item = if let Some(document_item) = document_item {
document_item
} else {
let document_item = {
let document_router_path = next_router_path.join("_document".into());
PagesStructureItem::new(
get_next_package(project_root).join("document.js".into()),
pages_path.join("_document".into()),
page_extensions,
Some(get_next_package(project_root).join("document.js".into())),
document_router_path,
document_router_path,
)
};

let error_item = if let Some(error_item) = error_item {
error_item
} else {
let error_item = {
let error_router_path = next_router_path.join("_error".into());
PagesStructureItem::new(
get_next_package(project_root).join("error.js".into()),
pages_path.join("_error".into()),
page_extensions,
Some(get_next_package(project_root).join("error.js".into())),
error_router_path,
error_router_path,
)
Expand Down Expand Up @@ -355,19 +365,22 @@ async fn get_pages_structure_for_directory(
if let DirectoryContent::Entries(entries) = &*dir_content {
for (name, entry) in entries.iter() {
match entry {
DirectoryEntry::File(file_project_path) => {
DirectoryEntry::File(_) => {
let Some(basename) = page_basename(name, page_extensions_raw) else {
continue;
};
let item_next_router_path = match basename {
"index" => next_router_path,
_ => next_router_path.join(basename.into()),
};
let base_path = project_path.join(name.clone());
let item_original_name = next_router_path.join(basename.into());
items.push((
basename,
PagesStructureItem::new(
*file_project_path,
base_path,
page_extensions,
None,
item_next_router_path,
item_original_name,
),
Expand Down

0 comments on commit 35798bf

Please sign in to comment.