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>
This commit is contained in:
Alex Kirszenberg 2023-07-24 10:57:48 +02:00 committed by GitHub
parent c8eb7f3de0
commit 2cd0c8abc7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 39 deletions

View file

@ -207,6 +207,9 @@ impl NapiMiddleware {
struct NapiEntrypoints {
pub routes: Vec<NapiRoute>,
pub middleware: Option<NapiMiddleware>,
pub pages_document_endpoint: External<ExternalEndpoint>,
pub pages_app_endpoint: External<ExternalEndpoint>,
pub pages_error_endpoint: External<ExternalEndpoint>,
pub issues: Vec<NapiIssue>,
pub diagnostics: Vec<NapiDiagnostic>,
}
@ -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))

View file

@ -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<String, Route>,
pub middleware: Option<Middleware>,
pub pages_document_endpoint: Vc<Box<dyn Endpoint>>,
pub pages_app_endpoint: Vc<Box<dyn Endpoint>>,
pub pages_error_endpoint: Vc<Box<dyn Endpoint>>,
}

View file

@ -66,8 +66,33 @@ impl PagesProject {
#[turbo_tasks::function]
pub async fn routes(self: Vc<Self>) -> Result<Vc<Routes>> {
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<String, Route>,
page: Vc<PagesStructureItem>,
make_route: impl Fn(Vc<String>, Vc<String>, Vc<FileSystemPath>) -> 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<String, Route>,
dir: Vc<PagesDirectoryStructure>,
@ -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<Self>,
item: Vc<PagesStructureItem>,
ty: PageEndpointType,
) -> Result<Vc<Box<dyn Endpoint>>> {
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<Self>) -> Result<Vc<Box<dyn Endpoint>>> {
Ok(self.to_endpoint(
self.pages_structure().await?.document,
PageEndpointType::SsrOnly,
))
}
#[turbo_tasks::function]
pub async fn app_endpoint(self: Vc<Self>) -> Result<Vc<Box<dyn Endpoint>>> {
Ok(self.to_endpoint(self.pages_structure().await?.app, PageEndpointType::Html))
}
#[turbo_tasks::function]
pub async fn error_endpoint(self: Vc<Self>) -> Result<Vc<Box<dyn Endpoint>>> {
Ok(self.to_endpoint(self.pages_structure().await?.error, PageEndpointType::Html))
}
#[turbo_tasks::function]
fn project(&self) -> Vc<Project> {
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? {

View file

@ -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())
}

View file

@ -393,6 +393,9 @@ interface Middleware {
interface Entrypoints {
routes: Map<string, Route>
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,
}

View file

@ -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) {