Skip to content

Commit 5e175e3

Browse files
authored
refactor(turbopack/next-api): Make VcArc use OperationVc (#74479)
`VcArc` represents values passed through napi to next.js and back. Because these values exit the scope of turbo-tasks, similar to how `State` works, they must be operations, so that they're recomputed/"kept alive" when read. These changes were extracted from @sokra's original `OperationVc` work (mostly preserved here: #72776), though adapted significantly for the removal of the `OperationVc::new()` constructor.
1 parent f6b783a commit 5e175e3

File tree

11 files changed

+144
-133
lines changed

11 files changed

+144
-133
lines changed

crates/napi/src/next_api/endpoint.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ use next_api::{
1010
},
1111
};
1212
use tracing::Instrument;
13-
use turbo_tasks::{
14-
get_effects, Completion, Effects, OperationVc, ReadRef, ResolvedVc, Vc, VcValueType,
15-
};
13+
use turbo_tasks::{get_effects, Completion, Effects, OperationVc, ReadRef, Vc, VcValueType};
1614
use turbopack_core::{
1715
diagnostics::PlainDiagnostic,
1816
error::PrettyPrintError,
@@ -91,10 +89,10 @@ impl From<Option<WrittenEndpoint>> for NapiWrittenEndpoint {
9189
// some async functions (in this case `endpoint_write_to_disk`) can cause
9290
// higher-ranked lifetime errors. See https://github.com/rust-lang/rust/issues/102211
9391
// 2. the type_complexity clippy lint.
94-
pub struct ExternalEndpoint(pub VcArc<Vc<Box<dyn Endpoint>>>);
92+
pub struct ExternalEndpoint(pub VcArc<Box<dyn Endpoint>>);
9593

9694
impl Deref for ExternalEndpoint {
97-
type Target = VcArc<Vc<Box<dyn Endpoint>>>;
95+
type Target = VcArc<Box<dyn Endpoint>>;
9896

9997
fn deref(&self) -> &Self::Target {
10098
&self.0
@@ -135,9 +133,9 @@ struct WrittenEndpointWithIssues {
135133

136134
#[turbo_tasks::function]
137135
async fn get_written_endpoint_with_issues(
138-
endpoint: ResolvedVc<Box<dyn Endpoint>>,
136+
endpoint_op: OperationVc<Box<dyn Endpoint>>,
139137
) -> Result<Vc<WrittenEndpointWithIssues>> {
140-
let write_to_disk = endpoint_write_to_disk_operation(endpoint);
138+
let write_to_disk = endpoint_write_to_disk_operation(endpoint_op);
141139
let (written, issues, diagnostics, effects) =
142140
strongly_consistent_catch_collectables(write_to_disk).await?;
143141
Ok(WrittenEndpointWithIssues {
@@ -155,10 +153,10 @@ pub async fn endpoint_write_to_disk(
155153
#[napi(ts_arg_type = "{ __napiType: \"Endpoint\" }")] endpoint: External<ExternalEndpoint>,
156154
) -> napi::Result<TurbopackResult<NapiWrittenEndpoint>> {
157155
let turbo_tasks = endpoint.turbo_tasks().clone();
158-
let endpoint = ***endpoint;
156+
let endpoint_op = ***endpoint;
159157
let (written, issues, diags) = turbo_tasks
160158
.run_once(async move {
161-
let operation = get_written_endpoint_with_issues(endpoint);
159+
let operation = get_written_endpoint_with_issues(endpoint_op);
162160
let WrittenEndpointWithIssues {
163161
written,
164162
issues,
@@ -191,8 +189,8 @@ pub fn endpoint_server_changed_subscribe(
191189
func,
192190
move || {
193191
async move {
194-
let operation = subscribe_issues_and_diags(endpoint, issues);
195-
let result = operation.strongly_consistent().await?;
192+
let vc = subscribe_issues_and_diags(endpoint, issues);
193+
let result = vc.strongly_consistent().await?;
196194
result.effects.apply().await?;
197195
Ok(result)
198196
}
@@ -241,10 +239,10 @@ impl Eq for EndpointIssuesAndDiags {}
241239

242240
#[turbo_tasks::function]
243241
async fn subscribe_issues_and_diags(
244-
endpoint: ResolvedVc<Box<dyn Endpoint>>,
242+
endpoint_op: OperationVc<Box<dyn Endpoint>>,
245243
should_include_issues: bool,
246244
) -> Result<Vc<EndpointIssuesAndDiags>> {
247-
let changed = endpoint_server_changed_operation(endpoint);
245+
let changed = endpoint_server_changed_operation(endpoint_op);
248246

249247
if should_include_issues {
250248
let (changed_value, issues, diagnostics, effects) =
@@ -280,7 +278,7 @@ pub fn endpoint_client_changed_subscribe(
280278
func,
281279
move || {
282280
async move {
283-
let changed = endpoint.client_changed();
281+
let changed = endpoint.connect().client_changed();
284282
// We don't capture issues and diagnostics here since we don't want to be
285283
// notified when they change
286284
changed.strongly_consistent().await?;

crates/napi/src/next_api/project.rs

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ use napi::{
88
};
99
use next_api::{
1010
entrypoints::Entrypoints,
11+
operation::{
12+
EntrypointsOperation, InstrumentationOperation, MiddlewareOperation, RouteOperation,
13+
},
1114
project::{
12-
DefineEnv, DraftModeOptions, Instrumentation, Middleware, PartialProjectOptions, Project,
13-
ProjectContainer, ProjectOptions, WatchOptions,
15+
DefineEnv, DraftModeOptions, PartialProjectOptions, Project, ProjectContainer,
16+
ProjectOptions, WatchOptions,
1417
},
15-
route::{Endpoint, Route},
18+
route::Endpoint,
1619
};
1720
use next_core::tracing_presets::{
1821
TRACING_NEXT_OVERVIEW_TARGETS, TRACING_NEXT_TARGETS, TRACING_NEXT_TURBOPACK_TARGETS,
@@ -25,7 +28,8 @@ use tracing::Instrument;
2528
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Registry};
2629
use turbo_rcstr::RcStr;
2730
use turbo_tasks::{
28-
get_effects, Completion, Effects, ReadRef, ResolvedVc, TransientInstance, UpdateInfo, Vc,
31+
get_effects, Completion, Effects, OperationVc, ReadRef, ResolvedVc, TransientInstance,
32+
UpdateInfo, Vc,
2933
};
3034
use turbo_tasks_fs::{
3135
get_relative_path_to, util::uri_from_file, DiskFileSystem, FileContent, FileSystem,
@@ -539,56 +543,56 @@ struct NapiRoute {
539543
}
540544

541545
impl NapiRoute {
542-
fn from_route(pathname: String, value: Route, turbo_tasks: &NextTurboTasks) -> Self {
543-
let convert_endpoint = |endpoint: Vc<Box<dyn Endpoint>>| {
546+
fn from_route(pathname: String, value: RouteOperation, turbo_tasks: &NextTurboTasks) -> Self {
547+
let convert_endpoint = |endpoint: OperationVc<Box<dyn Endpoint>>| {
544548
Some(External::new(ExternalEndpoint(VcArc::new(
545549
turbo_tasks.clone(),
546550
endpoint,
547551
))))
548552
};
549553
match value {
550-
Route::Page {
554+
RouteOperation::Page {
551555
html_endpoint,
552556
data_endpoint,
553557
} => NapiRoute {
554558
pathname,
555559
r#type: "page",
556-
html_endpoint: convert_endpoint(*html_endpoint),
557-
data_endpoint: convert_endpoint(*data_endpoint),
560+
html_endpoint: convert_endpoint(html_endpoint),
561+
data_endpoint: convert_endpoint(data_endpoint),
558562
..Default::default()
559563
},
560-
Route::PageApi { endpoint } => NapiRoute {
564+
RouteOperation::PageApi { endpoint } => NapiRoute {
561565
pathname,
562566
r#type: "page-api",
563-
endpoint: convert_endpoint(*endpoint),
567+
endpoint: convert_endpoint(endpoint),
564568
..Default::default()
565569
},
566-
Route::AppPage(pages) => NapiRoute {
570+
RouteOperation::AppPage(pages) => NapiRoute {
567571
pathname,
568572
r#type: "app-page",
569573
pages: Some(
570574
pages
571575
.into_iter()
572576
.map(|page_route| AppPageNapiRoute {
573-
original_name: Some(page_route.original_name),
577+
original_name: Some(page_route.original_name.into_owned()),
574578
html_endpoint: convert_endpoint(page_route.html_endpoint),
575579
rsc_endpoint: convert_endpoint(page_route.rsc_endpoint),
576580
})
577581
.collect(),
578582
),
579583
..Default::default()
580584
},
581-
Route::AppRoute {
585+
RouteOperation::AppRoute {
582586
original_name,
583587
endpoint,
584588
} => NapiRoute {
585589
pathname,
586-
original_name: Some(original_name),
590+
original_name: Some(original_name.into_owned()),
587591
r#type: "app-route",
588-
endpoint: convert_endpoint(*endpoint),
592+
endpoint: convert_endpoint(endpoint),
589593
..Default::default()
590594
},
591-
Route::Conflict => NapiRoute {
595+
RouteOperation::Conflict => NapiRoute {
592596
pathname,
593597
r#type: "conflict",
594598
..Default::default()
@@ -603,7 +607,7 @@ struct NapiMiddleware {
603607
}
604608

605609
impl NapiMiddleware {
606-
fn from_middleware(value: &Middleware, turbo_tasks: &NextTurboTasks) -> Result<Self> {
610+
fn from_middleware(value: &MiddlewareOperation, turbo_tasks: &NextTurboTasks) -> Result<Self> {
607611
Ok(NapiMiddleware {
608612
endpoint: External::new(ExternalEndpoint(VcArc::new(
609613
turbo_tasks.clone(),
@@ -620,7 +624,10 @@ struct NapiInstrumentation {
620624
}
621625

622626
impl NapiInstrumentation {
623-
fn from_instrumentation(value: &Instrumentation, turbo_tasks: &NextTurboTasks) -> Result<Self> {
627+
fn from_instrumentation(
628+
value: &InstrumentationOperation,
629+
turbo_tasks: &NextTurboTasks,
630+
) -> Result<Self> {
624631
Ok(NapiInstrumentation {
625632
node_js: External::new(ExternalEndpoint(VcArc::new(
626633
turbo_tasks.clone(),
@@ -644,9 +651,9 @@ struct NapiEntrypoints {
644651
pub pages_error_endpoint: External<ExternalEndpoint>,
645652
}
646653

647-
#[turbo_tasks::value(serialization = "none", local)]
654+
#[turbo_tasks::value(serialization = "none")]
648655
struct EntrypointsWithIssues {
649-
entrypoints: ReadRef<Entrypoints>,
656+
entrypoints: ReadRef<EntrypointsOperation>,
650657
issues: Arc<Vec<ReadRef<PlainIssue>>>,
651658
diagnostics: Arc<Vec<ReadRef<PlainDiagnostic>>>,
652659
effects: Arc<Effects>,
@@ -656,7 +663,8 @@ struct EntrypointsWithIssues {
656663
async fn get_entrypoints_with_issues(
657664
container: ResolvedVc<ProjectContainer>,
658665
) -> Result<Vc<EntrypointsWithIssues>> {
659-
let entrypoints_operation = project_container_entrypoints_operation(container);
666+
let entrypoints_operation =
667+
EntrypointsOperation::new(project_container_entrypoints_operation(container));
660668
let entrypoints = entrypoints_operation
661669
.connect()
662670
.strongly_consistent()
@@ -675,6 +683,8 @@ async fn get_entrypoints_with_issues(
675683

676684
#[turbo_tasks::function(operation)]
677685
fn project_container_entrypoints_operation(
686+
// the container is a long-lived object with internally mutable state, there's no risk of it
687+
// becoming stale
678688
container: ResolvedVc<ProjectContainer>,
679689
) -> Vc<Entrypoints> {
680690
container.entrypoints()
@@ -732,15 +742,15 @@ pub fn project_entrypoints_subscribe(
732742
.transpose()?,
733743
pages_document_endpoint: External::new(ExternalEndpoint(VcArc::new(
734744
turbo_tasks.clone(),
735-
*entrypoints.pages_document_endpoint,
745+
entrypoints.pages_document_endpoint,
736746
))),
737747
pages_app_endpoint: External::new(ExternalEndpoint(VcArc::new(
738748
turbo_tasks.clone(),
739-
*entrypoints.pages_app_endpoint,
749+
entrypoints.pages_app_endpoint,
740750
))),
741751
pages_error_endpoint: External::new(ExternalEndpoint(VcArc::new(
742752
turbo_tasks.clone(),
743-
*entrypoints.pages_error_endpoint,
753+
entrypoints.pages_error_endpoint,
744754
))),
745755
},
746756
issues: issues
@@ -782,7 +792,7 @@ async fn hmr_update(
782792
}
783793

784794
#[turbo_tasks::function(operation)]
785-
async fn project_hmr_update_operation(
795+
fn project_hmr_update_operation(
786796
project: ResolvedVc<Project>,
787797
identifier: RcStr,
788798
state: ResolvedVc<VersionState>,

crates/napi/src/next_api/utils.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,12 @@ pub fn create_turbo_tasks(
175175
#[derive(Clone)]
176176
pub struct VcArc<T> {
177177
turbo_tasks: NextTurboTasks,
178-
/// The Vc. Must be resolved, otherwise you are referencing an inactive
179-
/// operation.
180-
vc: T,
178+
/// The Vc. Must be unresolved, otherwise you are referencing an inactive operation.
179+
vc: OperationVc<T>,
181180
}
182181

183182
impl<T> VcArc<T> {
184-
pub fn new(turbo_tasks: NextTurboTasks, vc: T) -> Self {
183+
pub fn new(turbo_tasks: NextTurboTasks, vc: OperationVc<T>) -> Self {
185184
Self { turbo_tasks, vc }
186185
}
187186

@@ -191,7 +190,7 @@ impl<T> VcArc<T> {
191190
}
192191

193192
impl<T> Deref for VcArc<T> {
194-
type Target = T;
193+
type Target = OperationVc<T>;
195194

196195
fn deref(&self) -> &Self::Target {
197196
&self.vc

crates/next-api/src/app.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -804,8 +804,8 @@ pub fn app_entry_point_to_route(
804804
pages
805805
.into_iter()
806806
.map(|page| AppPageRoute {
807-
original_name: page.to_string(),
808-
html_endpoint: Vc::upcast(
807+
original_name: RcStr::from(page.to_string()),
808+
html_endpoint: ResolvedVc::upcast(
809809
AppEndpoint {
810810
ty: AppEndpointType::Page {
811811
ty: AppPageEndpointType::Html,
@@ -814,9 +814,9 @@ pub fn app_entry_point_to_route(
814814
app_project,
815815
page: page.clone(),
816816
}
817-
.cell(),
817+
.resolved_cell(),
818818
),
819-
rsc_endpoint: Vc::upcast(
819+
rsc_endpoint: ResolvedVc::upcast(
820820
AppEndpoint {
821821
ty: AppEndpointType::Page {
822822
ty: AppPageEndpointType::Rsc,
@@ -825,7 +825,7 @@ pub fn app_entry_point_to_route(
825825
app_project,
826826
page,
827827
}
828-
.cell(),
828+
.resolved_cell(),
829829
),
830830
})
831831
.collect(),
@@ -835,7 +835,7 @@ pub fn app_entry_point_to_route(
835835
path,
836836
root_layouts,
837837
} => Route::AppRoute {
838-
original_name: page.to_string(),
838+
original_name: page.to_string().into(),
839839
endpoint: ResolvedVc::upcast(
840840
AppEndpoint {
841841
ty: AppEndpointType::Route { path, root_layouts },
@@ -846,7 +846,7 @@ pub fn app_entry_point_to_route(
846846
),
847847
},
848848
AppEntrypoint::AppMetadata { page, metadata } => Route::AppRoute {
849-
original_name: page.to_string(),
849+
original_name: page.to_string().into(),
850850
endpoint: ResolvedVc::upcast(
851851
AppEndpoint {
852852
ty: AppEndpointType::Metadata { metadata },

crates/next-api/src/entrypoints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
route::{Endpoint, Route},
77
};
88

9-
#[turbo_tasks::value(shared, local)]
9+
#[turbo_tasks::value(shared)]
1010
pub struct Entrypoints {
1111
pub routes: FxIndexMap<RcStr, Route>,
1212
pub middleware: Option<Middleware>,

crates/next-api/src/global_module_id_strategy.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,12 @@ impl GlobalModuleIdStrategyBuilder {
3131
preprocessed_module_ids.push(preprocess_module_ids(*entrypoints.pages_document_endpoint));
3232

3333
if let Some(middleware) = &entrypoints.middleware {
34-
preprocessed_module_ids.push(preprocess_module_ids(middleware.endpoint));
34+
preprocessed_module_ids.push(preprocess_module_ids(*middleware.endpoint));
3535
}
3636

3737
if let Some(instrumentation) = &entrypoints.instrumentation {
38-
let node_js = instrumentation.node_js;
39-
let edge = instrumentation.edge;
40-
preprocessed_module_ids.push(preprocess_module_ids(node_js));
41-
preprocessed_module_ids.push(preprocess_module_ids(edge));
38+
preprocessed_module_ids.push(preprocess_module_ids(*instrumentation.node_js));
39+
preprocessed_module_ids.push(preprocess_module_ids(*instrumentation.edge));
4240
}
4341

4442
for (_, route) in entrypoints.routes.iter() {
@@ -56,9 +54,9 @@ impl GlobalModuleIdStrategyBuilder {
5654
Route::AppPage(page_routes) => {
5755
for page_route in page_routes {
5856
preprocessed_module_ids
59-
.push(preprocess_module_ids(page_route.html_endpoint));
57+
.push(preprocess_module_ids(*page_route.html_endpoint));
6058
preprocessed_module_ids
61-
.push(preprocess_module_ids(page_route.rsc_endpoint));
59+
.push(preprocess_module_ids(*page_route.rsc_endpoint));
6260
}
6361
}
6462
Route::AppRoute {

crates/next-api/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod loadable_manifest;
1515
mod middleware;
1616
mod module_graph;
1717
mod nft_json;
18+
pub mod operation;
1819
mod pages;
1920
pub mod paths;
2021
pub mod project;

0 commit comments

Comments
 (0)