From 2cd0c8abc79532ab462c5de08a8dbc048471d9eb Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 24 Jul 2023 10:57:48 +0200 Subject: [PATCH] Add app, error, and document entrypoints (#53013) ### What adds endpoints for `_app` `_error` and `_document` for pages Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> --- .../crates/napi/src/next_api/project.rs | 15 +++ .../crates/next-api/src/entrypoints.rs | 9 +- .../next-swc/crates/next-api/src/pages.rs | 125 +++++++++++++----- .../next-swc/crates/next-api/src/project.rs | 3 + packages/next/src/build/swc/index.ts | 13 ++ packages/next/src/cli/next-dev.ts | 20 ++- 6 files changed, 146 insertions(+), 39 deletions(-) diff --git a/packages/next-swc/crates/napi/src/next_api/project.rs b/packages/next-swc/crates/napi/src/next_api/project.rs index ae0b6881bf06e..a1a677c3d4d8b 100644 --- a/packages/next-swc/crates/napi/src/next_api/project.rs +++ b/packages/next-swc/crates/napi/src/next_api/project.rs @@ -207,6 +207,9 @@ impl NapiMiddleware { struct NapiEntrypoints { pub routes: Vec, pub middleware: Option, + pub pages_document_endpoint: External, + pub pages_app_endpoint: External, + pub pages_error_endpoint: External, pub issues: Vec, pub diagnostics: Vec, } @@ -245,6 +248,18 @@ pub fn project_entrypoints_subscribe( .as_ref() .map(|m| NapiMiddleware::from_middleware(m, &turbo_tasks)) .transpose()?, + pages_document_endpoint: External::new(ExternalEndpoint(VcArc::new( + turbo_tasks.clone(), + entrypoints.pages_document_endpoint, + ))), + pages_app_endpoint: External::new(ExternalEndpoint(VcArc::new( + turbo_tasks.clone(), + entrypoints.pages_app_endpoint, + ))), + pages_error_endpoint: External::new(ExternalEndpoint(VcArc::new( + turbo_tasks.clone(), + entrypoints.pages_error_endpoint, + ))), issues: issues .iter() .map(|issue| NapiIssue::from(&**issue)) diff --git a/packages/next-swc/crates/next-api/src/entrypoints.rs b/packages/next-swc/crates/next-api/src/entrypoints.rs index 751d1d3cd4a76..9268ba6dc1818 100644 --- a/packages/next-swc/crates/next-api/src/entrypoints.rs +++ b/packages/next-swc/crates/next-api/src/entrypoints.rs @@ -1,9 +1,16 @@ use indexmap::IndexMap; +use turbo_tasks::Vc; -use crate::{project::Middleware, route::Route}; +use crate::{ + project::Middleware, + route::{Endpoint, Route}, +}; #[turbo_tasks::value(shared)] pub struct Entrypoints { pub routes: IndexMap, pub middleware: Option, + pub pages_document_endpoint: Vc>, + pub pages_app_endpoint: Vc>, + pub pages_error_endpoint: Vc>, } diff --git a/packages/next-swc/crates/next-api/src/pages.rs b/packages/next-swc/crates/next-api/src/pages.rs index 835e6d9a4d65f..1a741eaa581bb 100644 --- a/packages/next-swc/crates/next-api/src/pages.rs +++ b/packages/next-swc/crates/next-api/src/pages.rs @@ -66,8 +66,33 @@ impl PagesProject { #[turbo_tasks::function] pub async fn routes(self: Vc) -> Result> { - let PagesStructure { api, pages, .. } = &*self.pages_structure().await?; + let PagesStructure { + api, + pages, + app: _, + document: _, + error: _, + } = &*self.pages_structure().await?; let mut routes = IndexMap::new(); + + async fn add_page_to_routes( + routes: &mut IndexMap, + page: Vc, + make_route: impl Fn(Vc, Vc, Vc) -> Route, + ) -> Result<()> { + let PagesStructureItem { + next_router_path, + project_path, + original_path, + } = *page.await?; + let pathname = format!("/{}", next_router_path.await?.path); + let pathname_vc = Vc::cell(pathname.clone()); + let original_name = Vc::cell(format!("/{}", original_path.await?.path)); + let route = make_route(pathname_vc, original_name, project_path); + routes.insert(pathname, route); + Ok(()) + } + async fn add_dir_to_routes( routes: &mut IndexMap, dir: Vc, @@ -82,16 +107,7 @@ impl PagesProject { project_path: _, } = *dir.await?; for &item in items.iter() { - let PagesStructureItem { - next_router_path, - project_path, - original_path, - } = *item.await?; - let pathname = format!("/{}", next_router_path.await?.path); - let pathname_vc = Vc::cell(pathname.clone()); - let original_name = Vc::cell(format!("/{}", original_path.await?.path)); - let route = make_route(pathname_vc, original_name, project_path); - routes.insert(pathname, route); + add_page_to_routes(routes, item, &make_route).await?; } for &child in children.iter() { queue.push(child); @@ -99,6 +115,7 @@ impl PagesProject { } Ok(()) } + if let Some(api) = api { add_dir_to_routes(&mut routes, *api, |pathname, original_name, path| { Route::PageApi { @@ -113,30 +130,74 @@ impl PagesProject { }) .await?; } - if let Some(page) = pages { - add_dir_to_routes(&mut routes, *page, |pathname, original_name, path| { - Route::Page { - html_endpoint: Vc::upcast(PageEndpoint::new( - PageEndpointType::Html, - self, - pathname, - original_name, - path, - )), - data_endpoint: Vc::upcast(PageEndpoint::new( - PageEndpointType::Data, - self, - pathname, - original_name, - path, - )), - } - }) - .await?; + + let make_page_route = |pathname, original_name, path| Route::Page { + html_endpoint: Vc::upcast(PageEndpoint::new( + PageEndpointType::Html, + self, + pathname, + original_name, + path, + )), + data_endpoint: Vc::upcast(PageEndpoint::new( + PageEndpointType::Data, + self, + pathname, + original_name, + path, + )), + }; + + if let Some(pages) = pages { + add_dir_to_routes(&mut routes, *pages, make_page_route).await?; } + Ok(Vc::cell(routes)) } + #[turbo_tasks::function] + async fn to_endpoint( + self: Vc, + item: Vc, + ty: PageEndpointType, + ) -> Result>> { + let PagesStructureItem { + next_router_path, + project_path, + original_path, + } = *item.await?; + let pathname = format!("/{}", next_router_path.await?.path); + let pathname_vc = Vc::cell(pathname.clone()); + let original_name = Vc::cell(format!("/{}", original_path.await?.path)); + let path = project_path; + let endpoint = Vc::upcast(PageEndpoint::new( + ty, + self, + pathname_vc, + original_name, + path, + )); + Ok(endpoint) + } + + #[turbo_tasks::function] + pub async fn document_endpoint(self: Vc) -> Result>> { + Ok(self.to_endpoint( + self.pages_structure().await?.document, + PageEndpointType::SsrOnly, + )) + } + + #[turbo_tasks::function] + pub async fn app_endpoint(self: Vc) -> Result>> { + Ok(self.to_endpoint(self.pages_structure().await?.app, PageEndpointType::Html)) + } + + #[turbo_tasks::function] + pub async fn error_endpoint(self: Vc) -> Result>> { + Ok(self.to_endpoint(self.pages_structure().await?.error, PageEndpointType::Html)) + } + #[turbo_tasks::function] fn project(&self) -> Vc { self.project @@ -407,6 +468,7 @@ enum PageEndpointType { Api, Html, Data, + SsrOnly, } #[turbo_tasks::value_impl] @@ -665,6 +727,7 @@ impl PageEndpoint { } PageEndpointType::Data => self.ssr_data_chunk(), PageEndpointType::Api => self.api_chunk(), + PageEndpointType::SsrOnly => self.ssr_chunk(), }; let page_output = match *ssr_chunk.await? { diff --git a/packages/next-swc/crates/next-api/src/project.rs b/packages/next-swc/crates/next-api/src/project.rs index d3349114d409d..8b9463cc20fbc 100644 --- a/packages/next-swc/crates/next-api/src/project.rs +++ b/packages/next-swc/crates/next-api/src/project.rs @@ -373,6 +373,9 @@ impl Project { Ok(Entrypoints { routes, middleware: None, + pages_document_endpoint: self.pages_project().document_endpoint(), + pages_app_endpoint: self.pages_project().app_endpoint(), + pages_error_endpoint: self.pages_project().error_endpoint(), } .cell()) } diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index 76fcf6691d8f5..9bdbd5b32a2db 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -393,6 +393,9 @@ interface Middleware { interface Entrypoints { routes: Map middleware?: Middleware + pagesDocumentEndpoint: Endpoint + pagesAppEndpoint: Endpoint + pagesErrorEndpoint: Endpoint } interface Project { @@ -587,6 +590,9 @@ function bindingToApi(binding: any, _wasm: boolean) { type NapiEntrypoints = { routes: NapiRoute[] middleware?: NapiMiddleware + pagesDocumentEndpoint: NapiEndpoint + pagesAppEndpoint: NapiEndpoint + pagesErrorEndpoint: NapiEndpoint issues: Issue[] diagnostics: Diagnostics[] } @@ -683,6 +689,13 @@ function bindingToApi(binding: any, _wasm: boolean) { yield { routes, middleware, + pagesDocumentEndpoint: new EndpointImpl( + entrypoints.pagesDocumentEndpoint + ), + pagesAppEndpoint: new EndpointImpl(entrypoints.pagesAppEndpoint), + pagesErrorEndpoint: new EndpointImpl( + entrypoints.pagesErrorEndpoint + ), issues: entrypoints.issues, diagnostics: entrypoints.diagnostics, } diff --git a/packages/next/src/cli/next-dev.ts b/packages/next/src/cli/next-dev.ts index db94c00f5c832..d246939d7823e 100644 --- a/packages/next/src/cli/next-dev.ts +++ b/packages/next/src/cli/next-dev.ts @@ -240,20 +240,29 @@ const nextDev: CliCommand = async (argv) => { // Just testing code here: - const project = await bindings.turbo.createProject({ + const options = { projectPath: dir, - rootPath: dir, + rootPath: args['--root'] ?? findRootDir(dir) ?? dir, nextConfig: config, env: { NEXT_PUBLIC_ENV_VAR: 'world', }, watch: true, - }) + } + const project = await bindings.turbo.createProject(options) const iter = project.entrypointsSubscribe() try { for await (const entrypoints of iter) { Log.info(entrypoints) + + Log.info(`writing _document to disk`) + Log.info(await entrypoints.pagesDocumentEndpoint.writeToDisk()) + Log.info(`writing _app to disk`) + Log.info(await entrypoints.pagesAppEndpoint.writeToDisk()) + Log.info(`writing _error to disk`) + Log.info(await entrypoints.pagesErrorEndpoint.writeToDisk()) + for (const [pathname, route] of entrypoints.routes) { switch (route.type) { case 'page': { @@ -287,13 +296,10 @@ const nextDev: CliCommand = async (argv) => { } Log.info('iteration done') await project.update({ - projectPath: dir, - rootPath: dir, - nextConfig: config, + ...options, env: { NEXT_PUBLIC_ENV_VAR: 'hello', }, - watch: true, }) } } catch (e) {