Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production builds: write endpoints all at once #75304

Open
wants to merge 12 commits into
base: canary
Choose a base branch
from
36 changes: 4 additions & 32 deletions crates/napi/src/next_api/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ use next_api::{
},
};
use tracing::Instrument;
use turbo_tasks::{get_effects, Completion, Effects, OperationVc, ReadRef, Vc, VcValueType};
use turbopack_core::{
diagnostics::PlainDiagnostic,
error::PrettyPrintError,
issue::{IssueSeverity, PlainIssue},
};
use turbo_tasks::{Completion, Effects, OperationVc, ReadRef, Vc};
use turbopack_core::{diagnostics::PlainDiagnostic, error::PrettyPrintError, issue::PlainIssue};

use super::utils::{
get_diagnostics, get_issues, subscribe, NapiDiagnostic, NapiIssue, RootTask, TurbopackResult,
VcArc,
strongly_consistent_catch_collectables, subscribe, NapiDiagnostic, NapiIssue, RootTask,
TurbopackResult, VcArc,
};

#[napi(object)]
Expand Down Expand Up @@ -99,30 +95,6 @@ impl Deref for ExternalEndpoint {
}
}

// Await the source and return fatal issues if there are any, otherwise
// propagate any actual error results.
async fn strongly_consistent_catch_collectables<R: VcValueType + Send>(
source_op: OperationVc<R>,
) -> Result<(
Option<ReadRef<R>>,
Arc<Vec<ReadRef<PlainIssue>>>,
Arc<Vec<ReadRef<PlainDiagnostic>>>,
Arc<Effects>,
)> {
let result = source_op.read_strongly_consistent().await;
let issues = get_issues(source_op).await?;
let diagnostics = get_diagnostics(source_op).await?;
let effects = Arc::new(get_effects(source_op).await?);

let result = if result.is_err() && issues.iter().any(|i| i.severity <= IssueSeverity::Error) {
None
} else {
Some(result?)
};

Ok((result, issues, diagnostics, effects))
}

#[turbo_tasks::value(serialization = "none")]
struct WrittenEndpointWithIssues {
written: Option<ReadRef<EndpointOutputPaths>>,
Expand Down
197 changes: 155 additions & 42 deletions crates/napi/src/next_api/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Registry};
use turbo_rcstr::RcStr;
use turbo_tasks::{
get_effects, Completion, Effects, OperationVc, ReadRef, ResolvedVc, TransientInstance,
UpdateInfo, Vc,
get_effects, Completion, Effects, FxIndexSet, OperationVc, ReadRef, ResolvedVc,
TransientInstance, TryJoinIterExt, UpdateInfo, Vc,
};
use turbo_tasks_fs::{
get_relative_path_to, util::uri_from_file, DiskFileSystem, FileContent, FileSystem,
Expand All @@ -39,6 +39,7 @@
diagnostics::PlainDiagnostic,
error::PrettyPrintError,
issue::PlainIssue,
output::{OutputAsset, OutputAssets},
source_map::{SourceMap, Token},
version::{PartialUpdate, TotalUpdate, Update, VersionState},
SOURCE_MAP_PREFIX,
Expand Down Expand Up @@ -537,7 +538,7 @@

#[napi(object)]
#[derive(Default)]
struct AppPageNapiRoute {
pub struct AppPageNapiRoute {
/// The relative path from project_path to the route file
pub original_name: Option<String>,

Expand All @@ -547,7 +548,7 @@

#[napi(object)]
#[derive(Default)]
struct NapiRoute {
pub struct NapiRoute {
/// The router path
pub pathname: String,
/// The relative path from project_path to the route file
Expand Down Expand Up @@ -625,7 +626,7 @@
}

#[napi(object)]
struct NapiMiddleware {
pub struct NapiMiddleware {
pub endpoint: External<ExternalEndpoint>,
}

Expand All @@ -641,7 +642,7 @@
}

#[napi(object)]
struct NapiInstrumentation {
pub struct NapiInstrumentation {
pub node_js: External<ExternalEndpoint>,
pub edge: External<ExternalEndpoint>,
}
Expand All @@ -665,7 +666,7 @@
}

#[napi(object)]
struct NapiEntrypoints {
pub struct NapiEntrypoints {
pub routes: Vec<NapiRoute>,
pub middleware: Option<NapiMiddleware>,
pub instrumentation: Option<NapiInstrumentation>,
Expand All @@ -674,6 +675,49 @@
pub pages_error_endpoint: External<ExternalEndpoint>,
}

impl NapiEntrypoints {
fn from_entrypoints_op(
entrypoints: &EntrypointsOperation,
turbo_tasks: &NextTurboTasks,
) -> Result<Self> {
let routes = entrypoints
.routes
.iter()
.map(|(k, v)| NapiRoute::from_route(k.to_string(), v.clone(), turbo_tasks))
.collect();
let middleware = entrypoints
.middleware
.as_ref()
.map(|m| NapiMiddleware::from_middleware(m, turbo_tasks))
.transpose()?;
let instrumentation = entrypoints
.instrumentation
.as_ref()
.map(|i| NapiInstrumentation::from_instrumentation(i, turbo_tasks))
.transpose()?;
let pages_document_endpoint = External::new(ExternalEndpoint(VcArc::new(
turbo_tasks.clone(),
entrypoints.pages_document_endpoint,
)));
let pages_app_endpoint = External::new(ExternalEndpoint(VcArc::new(
turbo_tasks.clone(),
entrypoints.pages_app_endpoint,
)));
let pages_error_endpoint = External::new(ExternalEndpoint(VcArc::new(
turbo_tasks.clone(),
entrypoints.pages_error_endpoint,
)));
Ok(NapiEntrypoints {
routes,
middleware,
instrumentation,
pages_document_endpoint,
pages_app_endpoint,
pages_error_endpoint,
})
}
}

#[turbo_tasks::value(serialization = "none")]
struct EntrypointsWithIssues {
entrypoints: ReadRef<EntrypointsOperation>,
Expand Down Expand Up @@ -710,6 +754,109 @@
container.entrypoints()
}

#[turbo_tasks::value(serialization = "none")]
struct AllWrittenEntrypointsWithIssues {
entrypoints: Option<ReadRef<Entrypoints>>,
issues: Arc<Vec<ReadRef<PlainIssue>>>,
diagnostics: Arc<Vec<ReadRef<PlainDiagnostic>>>,
effects: Arc<Effects>,
}

#[napi]
pub async fn project_write_all_entrypoints_to_disk(
#[napi(ts_arg_type = "{ __napiType: \"Project\" }")] project: External<ProjectInstance>,
app_dir_only: bool,
) -> napi::Result<TurbopackResult<NapiEntrypoints>> {
let turbo_tasks = project.turbo_tasks.clone();
let (entrypoints, issues, diags) = turbo_tasks
.run_once(async move {
let entrypoints_with_issues_op = get_all_written_entrypoints_with_issues_operation(
project.container.to_resolved().await?,
ResolvedVc::cell(app_dir_only),
);

let EntrypointsWithIssues {
entrypoints,
issues,
diagnostics,
effects,
} = &*entrypoints_with_issues_op
.read_strongly_consistent()
.await?;
effects.apply().await?;

Ok((entrypoints.clone(), issues.clone(), diagnostics.clone()))
})
.await
.map_err(|e| napi::Error::from_reason(PrettyPrintError(&e).to_string()))?;

Ok(TurbopackResult {
result: NapiEntrypoints::from_entrypoints_op(&entrypoints, &turbo_tasks)?,
issues: issues.iter().map(|i| NapiIssue::from(&**i)).collect(),
diagnostics: diags.iter().map(|d| NapiDiagnostic::from(d)).collect(),
})
}

#[turbo_tasks::function(operation)]
async fn get_all_written_entrypoints_with_issues_operation(
container: ResolvedVc<ProjectContainer>,
app_dir_only: ResolvedVc<bool>,
) -> Result<Vc<EntrypointsWithIssues>> {
let entrypoints_operation = EntrypointsOperation::new(all_entrypoints_write_to_disk_operation(
container,
app_dir_only,
));
let entrypoints = entrypoints_operation.read_strongly_consistent().await?;
let issues = get_issues(entrypoints_operation).await?;
let diagnostics = get_diagnostics(entrypoints_operation).await?;
let effects = Arc::new(get_effects(entrypoints_operation).await?);
Ok(EntrypointsWithIssues {
entrypoints,
issues,
diagnostics,
effects,
}
.cell())
}

#[turbo_tasks::function(operation)]
pub async fn all_entrypoints_write_to_disk_operation(
project: ResolvedVc<ProjectContainer>,
app_dir_only: ResolvedVc<bool>,
) -> Result<Vc<Entrypoints>> {
let _ = project
.project()
.emit_all_output_assets(output_assets_operation(project, app_dir_only))
.resolve()
.await?;

Ok(project.entrypoints())
}

#[turbo_tasks::function(operation)]
async fn output_assets_operation(
container: ResolvedVc<ProjectContainer>,
app_dir_only: ResolvedVc<bool>,
) -> Result<Vc<OutputAssets>> {
let app_dir_only = *app_dir_only.await?;

let endpoint_assets = container
.project()
.get_all_endpoints(app_dir_only)
.await?
.iter()
.map(|endpoint| async move { endpoint.output().await?.output_assets.await })
.try_join()
.await?;

let mut output_assets: FxIndexSet<ResolvedVc<Box<dyn OutputAsset>>> = FxIndexSet::default();
for assets in endpoint_assets {
output_assets.extend(assets.iter());
}

Ok(Vc::cell(output_assets.into_iter().collect()))
}

#[napi(ts_return_type = "{ __napiType: \"RootTask\" }")]
pub fn project_entrypoints_subscribe(
#[napi(ts_arg_type = "{ __napiType: \"Project\" }")] project: External<ProjectInstance>,
Expand Down Expand Up @@ -741,41 +888,7 @@
let (entrypoints, issues, diags) = ctx.value;

Ok(vec![TurbopackResult {
result: NapiEntrypoints {
routes: entrypoints
.routes
.iter()
.map(|(pathname, route)| {
NapiRoute::from_route(
pathname.clone().into(),
route.clone(),
&turbo_tasks,
)
})
.collect::<Vec<_>>(),
middleware: entrypoints
.middleware
.as_ref()
.map(|m| NapiMiddleware::from_middleware(m, &turbo_tasks))
.transpose()?,
instrumentation: entrypoints
.instrumentation
.as_ref()
.map(|m| NapiInstrumentation::from_instrumentation(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,
))),
},
result: NapiEntrypoints::from_entrypoints_op(&entrypoints, &turbo_tasks)?,
issues: issues
.iter()
.map(|issue| NapiIssue::from(&**issue))
Expand Down Expand Up @@ -1039,7 +1152,7 @@
}
}

/// Subscribes to lifecycle events of the compilation.

Check warning on line 1155 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::Start`

Check warning on line 1155 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::End`

Check warning on line 1155 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::End`

Check warning on line 1155 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::Start`
///
/// Emits an [UpdateMessage::Start] event when any computation starts.
/// Emits an [UpdateMessage::End] event when there was no computation for the
Expand Down
32 changes: 29 additions & 3 deletions crates/napi/src/next_api/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use napi::{
};
use serde::Serialize;
use turbo_tasks::{
task_statistics::TaskStatisticsApi, trace::TraceRawVcs, OperationVc, ReadRef, TaskId,
TryJoinIterExt, TurboTasks, TurboTasksApi, UpdateInfo, Vc,
get_effects, task_statistics::TaskStatisticsApi, trace::TraceRawVcs, Effects, OperationVc,
ReadRef, TaskId, TryJoinIterExt, TurboTasks, TurboTasksApi, UpdateInfo, Vc, VcValueType,
};
use turbo_tasks_backend::{
default_backing_storage, noop_backing_storage, DefaultBackingStorage, NoopBackingStorage,
Expand All @@ -20,7 +20,9 @@ use turbo_tasks_fs::FileContent;
use turbopack_core::{
diagnostics::{Diagnostic, DiagnosticContextExt, PlainDiagnostic},
error::PrettyPrintError,
issue::{IssueDescriptionExt, PlainIssue, PlainIssueSource, PlainSource, StyledString},
issue::{
IssueDescriptionExt, IssueSeverity, PlainIssue, PlainIssueSource, PlainSource, StyledString,
},
source_pos::SourcePos,
};

Expand Down Expand Up @@ -495,3 +497,27 @@ pub fn subscribe<T: 'static + Send + Sync, F: Future<Output = Result<T>> + Send,
task_id: Some(task_id),
}))
}

// Await the source and return fatal issues if there are any, otherwise
// propagate any actual error results.
pub async fn strongly_consistent_catch_collectables<R: VcValueType + Send>(
source_op: OperationVc<R>,
) -> Result<(
Option<ReadRef<R>>,
Arc<Vec<ReadRef<PlainIssue>>>,
Arc<Vec<ReadRef<PlainDiagnostic>>>,
Arc<Effects>,
)> {
let result = source_op.read_strongly_consistent().await;
let issues = get_issues(source_op).await?;
let diagnostics = get_diagnostics(source_op).await?;
let effects = Arc::new(get_effects(source_op).await?);

let result = if result.is_err() && issues.iter().any(|i| i.severity <= IssueSeverity::Error) {
None
} else {
Some(result?)
};

Ok((result, issues, diagnostics, effects))
}
Loading
Loading