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

[Turbopack] add feature flag to use the new backend in next.js #68823

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ swc-ast-explorer = { path = "turbopack/crates/turbopack-swc-ast-explorer" }
turbo-prehash = { path = "turbopack/crates/turbo-prehash" }
turbo-tasks-malloc = { path = "turbopack/crates/turbo-tasks-malloc", default-features = false }
turbo-tasks = { path = "turbopack/crates/turbo-tasks" }
turbo-tasks-backend = { path = "turbopack/crates/turbo-tasks-backend" }
turbo-tasks-build = { path = "turbopack/crates/turbo-tasks-build" }
turbo-tasks-bytes = { path = "turbopack/crates/turbo-tasks-bytes" }
turbo-tasks-env = { path = "turbopack/crates/turbo-tasks-env" }
Expand Down
3 changes: 3 additions & 0 deletions crates/napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ __internal_dhat-heap = ["dhat"]
# effectively does nothing.
__internal_dhat-ad-hoc = ["dhat"]

new-backend = ["dep:turbo-tasks-backend"]

# Enable specific tls features per-target.
[target.'cfg(all(target_os = "windows", target_arch = "aarch64"))'.dependencies]
next-core = { workspace = true, features = ["native-tls"] }
Expand Down Expand Up @@ -105,6 +107,7 @@ lightningcss-napi = { workspace = true }
tokio = { workspace = true, features = ["full"] }
turbo-tasks = { workspace = true }
turbo-tasks-memory = { workspace = true }
turbo-tasks-backend = { workspace = true, optional = true }
turbo-tasks-fs = { workspace = true }
next-api = { workspace = true }
next-build = { workspace = true }
Expand Down
7 changes: 3 additions & 4 deletions crates/napi/src/app_structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ use turbo_tasks::{
ValueToString, Vc,
};
use turbo_tasks_fs::{DiskFileSystem, FileSystem, FileSystemPath};
use turbo_tasks_memory::MemoryBackend;
use turbopack_core::PROJECT_FILESYSTEM_NAME;

use crate::register;
use crate::{next_api::utils::NextBackend, register};

#[turbo_tasks::function]
async fn project_fs(project_dir: RcStr, watching: bool) -> Result<Vc<Box<dyn FileSystem>>> {
Expand Down Expand Up @@ -365,7 +364,7 @@ async fn get_value(

#[napi]
pub fn stream_entrypoints(
turbo_tasks: External<Arc<TurboTasks<MemoryBackend>>>,
turbo_tasks: External<Arc<TurboTasks<NextBackend>>>,
root_dir: String,
project_dir: String,
page_extensions: Vec<String>,
Expand Down Expand Up @@ -411,7 +410,7 @@ pub fn stream_entrypoints(

#[napi]
pub async fn get_entrypoints(
turbo_tasks: External<Arc<TurboTasks<MemoryBackend>>>,
turbo_tasks: External<Arc<TurboTasks<NextBackend>>>,
root_dir: String,
project_dir: String,
page_extensions: Vec<String>,
Expand Down
67 changes: 33 additions & 34 deletions crates/napi/src/next_api/project.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{io::Write, path::PathBuf, sync::Arc, thread, time::Duration};
use std::{path::PathBuf, sync::Arc, thread, time::Duration};

use anyhow::{anyhow, bail, Context, Result};
use napi::{
Expand All @@ -24,7 +24,6 @@
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
use turbo_tasks::{Completion, RcStr, ReadRef, TransientInstance, TurboTasks, UpdateInfo, Vc};
use turbo_tasks_fs::{DiskFileSystem, FileContent, FileSystem, FileSystemPath};
use turbo_tasks_memory::MemoryBackend;
use turbopack_core::{
diagnostics::PlainDiagnostic,
error::PrettyPrintError,
Expand All @@ -44,8 +43,8 @@
use super::{
endpoint::ExternalEndpoint,
utils::{
get_diagnostics, get_issues, subscribe, NapiDiagnostic, NapiIssue, RootTask,
TurbopackResult, VcArc,
create_turbo_tasks, get_diagnostics, get_issues, subscribe, NapiDiagnostic, NapiIssue,
NextBackend, RootTask, TurbopackResult, VcArc,
},
};
use crate::register;
Expand Down Expand Up @@ -89,7 +88,7 @@

/// next.config's distDir. Project initialization occurs eariler than
/// deserializing next.config, so passing it as separate option.
pub dist_dir: Option<String>,
pub dist_dir: String,

/// Whether to watch he filesystem for file changes.
pub watch: bool,
Expand Down Expand Up @@ -244,7 +243,7 @@
}

pub struct ProjectInstance {
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: Arc<TurboTasks<NextBackend>>,
container: Vc<ProjectContainer>,
exit_receiver: tokio::sync::Mutex<Option<ExitReceiver>>,
}
Expand Down Expand Up @@ -280,10 +279,7 @@
let subscriber = Registry::default();

let subscriber = subscriber.with(EnvFilter::builder().parse(trace).unwrap());
let dist_dir = options
.dist_dir
.as_ref()
.map_or_else(|| ".next".to_string(), |d| d.to_string());
let dist_dir = options.dist_dir.clone();

let internal_dir = PathBuf::from(&options.project_path).join(dist_dir);
std::fs::create_dir_all(&internal_dir)
Expand All @@ -309,27 +305,30 @@
subscriber.init();
}

let turbo_tasks = TurboTasks::new(MemoryBackend::new(
turbo_engine_options
.memory_limit
.map(|m| m as usize)
.unwrap_or(usize::MAX),
));
let stats_path = std::env::var_os("NEXT_TURBOPACK_TASK_STATISTICS");
if let Some(stats_path) = stats_path {
let task_stats = turbo_tasks.backend().task_statistics().enable().clone();
exit.on_exit(async move {
tokio::task::spawn_blocking(move || {
let mut file = std::fs::File::create(&stats_path)
.with_context(|| format!("failed to create or open {stats_path:?}"))?;
serde_json::to_writer(&file, &task_stats)
.context("failed to serialize or write task statistics")?;
file.flush().context("failed to flush file")
})
.await
.unwrap()
.unwrap();
});
let memory_limit = turbo_engine_options
.memory_limit
.map(|m| m as usize)
.unwrap_or(usize::MAX);
let turbo_tasks = create_turbo_tasks(PathBuf::from(&options.dist_dir), memory_limit)?;
#[cfg(not(feature = "new-backend"))]
{
use std::io::Write;
let stats_path = std::env::var_os("NEXT_TURBOPACK_TASK_STATISTICS");
if let Some(stats_path) = stats_path {
let task_stats = turbo_tasks.backend().task_statistics().enable().clone();
exit.on_exit(async move {
tokio::task::spawn_blocking(move || {
let mut file = std::fs::File::create(&stats_path)
.with_context(|| format!("failed to create or open {stats_path:?}"))?;
serde_json::to_writer(&file, &task_stats)
.context("failed to serialize or write task statistics")?;
file.flush().context("failed to flush file")
})
.await
.unwrap()
.unwrap();
});
}
}
let options = options.into();
let container = turbo_tasks
Expand Down Expand Up @@ -463,7 +462,7 @@
fn from_route(
pathname: String,
value: Route,
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: &Arc<TurboTasks<NextBackend>>,
) -> Self {
let convert_endpoint = |endpoint: Vc<Box<dyn Endpoint>>| {
Some(External::new(ExternalEndpoint(VcArc::new(
Expand Down Expand Up @@ -530,7 +529,7 @@
impl NapiMiddleware {
fn from_middleware(
value: &Middleware,
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: &Arc<TurboTasks<NextBackend>>,
) -> Result<Self> {
Ok(NapiMiddleware {
endpoint: External::new(ExternalEndpoint(VcArc::new(
Expand All @@ -550,7 +549,7 @@
impl NapiInstrumentation {
fn from_instrumentation(
value: &Instrumentation,
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: &Arc<TurboTasks<NextBackend>>,
) -> Result<Self> {
Ok(NapiInstrumentation {
node_js: External::new(ExternalEndpoint(VcArc::new(
Expand Down Expand Up @@ -889,7 +888,7 @@
}
}

/// Subscribes to lifecycle events of the compilation.

Check warning on line 891 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 891 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 891 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 891 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
/// specified time (`aggregation_ms`). The [UpdateMessage::End] event contains
Expand Down
32 changes: 25 additions & 7 deletions crates/napi/src/next_api/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, future::Future, ops::Deref, sync::Arc};
use std::{collections::HashMap, future::Future, ops::Deref, path::PathBuf, sync::Arc};

use anyhow::{anyhow, Context, Result};
use napi::{
Expand All @@ -9,30 +9,48 @@ use napi::{
use serde::Serialize;
use turbo_tasks::{ReadRef, TaskId, TryJoinIterExt, TurboTasks, Vc};
use turbo_tasks_fs::FileContent;
use turbo_tasks_memory::MemoryBackend;
use turbopack_core::{
diagnostics::{Diagnostic, DiagnosticContextExt, PlainDiagnostic},
error::PrettyPrintError,
issue::{IssueDescriptionExt, PlainIssue, PlainIssueSource, PlainSource, StyledString},
source_pos::SourcePos,
};

#[cfg(not(feature = "new-backend"))]
pub type NextBackend = turbo_tasks_memory::MemoryBackend;
#[cfg(feature = "new-backend")]
pub type NextBackend = turbo_tasks_backend::TurboTasksBackend;

#[allow(unused_variables, reason = "feature-gated")]
pub fn create_turbo_tasks(
output_path: PathBuf,
memory_limit: usize,
) -> Result<Arc<TurboTasks<NextBackend>>> {
#[cfg(not(feature = "new-backend"))]
let backend = TurboTasks::new(turbo_tasks_memory::MemoryBackend::new(memory_limit));
#[cfg(feature = "new-backend")]
let backend = TurboTasks::new(turbo_tasks_backend::TurboTasksBackend::new(Arc::new(
turbo_tasks_backend::LmdbBackingStorage::new(&output_path.join("cache/turbopack"))?,
)));
Ok(backend)
}

/// A helper type to hold both a Vc operation and the TurboTasks root process.
/// Without this, we'd need to pass both individually all over the place
#[derive(Clone)]
pub struct VcArc<T> {
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: Arc<TurboTasks<NextBackend>>,
/// The Vc. Must be resolved, otherwise you are referencing an inactive
/// operation.
vc: T,
}

impl<T> VcArc<T> {
pub fn new(turbo_tasks: Arc<TurboTasks<MemoryBackend>>, vc: T) -> Self {
pub fn new(turbo_tasks: Arc<TurboTasks<NextBackend>>, vc: T) -> Self {
Self { turbo_tasks, vc }
}

pub fn turbo_tasks(&self) -> &Arc<TurboTasks<MemoryBackend>> {
pub fn turbo_tasks(&self) -> &Arc<TurboTasks<NextBackend>> {
&self.turbo_tasks
}
}
Expand All @@ -55,7 +73,7 @@ pub fn serde_enum_to_string<T: Serialize>(value: &T) -> Result<String> {
/// The root of our turbopack computation.
pub struct RootTask {
#[allow(dead_code)]
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: Arc<TurboTasks<NextBackend>>,
#[allow(dead_code)]
task_id: Option<TaskId>,
}
Expand Down Expand Up @@ -299,7 +317,7 @@ impl<T: ToNapiValue> ToNapiValue for TurbopackResult<T> {
}

pub fn subscribe<T: 'static + Send + Sync, F: Future<Output = Result<T>> + Send, V: ToNapiValue>(
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: Arc<TurboTasks<NextBackend>>,
func: JsFunction,
handler: impl 'static + Sync + Send + Clone + Fn() -> F,
mapper: impl 'static + Sync + Send + FnMut(ThreadSafeCallContext<T>) -> napi::Result<Vec<V>>,
Expand Down
26 changes: 13 additions & 13 deletions crates/napi/src/turbotrace.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
use std::sync::Arc;
use std::{path::PathBuf, sync::Arc};

use napi::bindgen_prelude::*;
use node_file_trace::{start, Args};
use turbo_tasks::TurboTasks;
use turbo_tasks_memory::MemoryBackend;
use turbopack::{
module_options::{EcmascriptOptionsContext, ModuleOptionsContext},
resolve_options_context::ResolveOptionsContext,
};

use crate::next_api::utils::{self, NextBackend};

#[napi]
pub fn create_turbo_tasks(memory_limit: Option<i64>) -> External<Arc<TurboTasks<MemoryBackend>>> {
let turbo_tasks = TurboTasks::new(MemoryBackend::new(
memory_limit.map(|m| m as usize).unwrap_or(usize::MAX),
));
External::new_with_size_hint(
turbo_tasks,
memory_limit.map(|u| u as usize).unwrap_or(usize::MAX),
)
pub fn create_turbo_tasks(
output_path: String,
memory_limit: Option<i64>,
) -> External<Arc<TurboTasks<NextBackend>>> {
let limit = memory_limit.map(|u| u as usize).unwrap_or(usize::MAX);
let turbo_tasks = utils::create_turbo_tasks(PathBuf::from(&output_path), limit)
.expect("Failed to create TurboTasks");
External::new_with_size_hint(turbo_tasks, limit)
}

#[napi]
pub async fn run_turbo_tracing(
options: Buffer,
turbo_tasks: Option<External<Arc<TurboTasks<MemoryBackend>>>>,
turbo_tasks: External<Arc<TurboTasks<NextBackend>>>,
) -> napi::Result<Vec<String>> {
let args: Args = serde_json::from_slice(options.as_ref())?;
let turbo_tasks = turbo_tasks.map(|t| t.clone());
let files = start(
Arc::new(args),
turbo_tasks.as_ref(),
turbo_tasks.clone(),
Some(ModuleOptionsContext {
ecmascript: EcmascriptOptionsContext {
enable_types: true,
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/collect-build-traces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export async function collectBuildTraces({
let turbotraceOutputPath: string | undefined
let turbotraceFiles: string[] | undefined
turboTasksForTrace = bindings.turbo.createTurboTasks(
distDir,
(config.experimental.turbotrace?.memoryLimit ??
TURBO_TRACE_DEFAULT_MEMORY_LIMIT) *
1024 *
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,7 @@ export default async function build(
{
projectPath: dir,
rootPath: config.outputFileTracingRoot || dir,
distDir,
nextConfig: config,
jsConfig: await getTurbopackJsConfig(dir, config),
watch: false,
Expand Down
14 changes: 11 additions & 3 deletions packages/next/src/build/swc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,11 @@ export interface ProjectOptions {
*/
projectPath: string

/**
* The path to the .next directory.
*/
distDir: string

/**
* The next.config.js contents.
*/
Expand Down Expand Up @@ -1547,15 +1552,18 @@ function loadNative(importPath?: string) {
initHeapProfiler: bindings.initHeapProfiler,
teardownHeapProfiler: bindings.teardownHeapProfiler,
turbo: {
startTrace: (options = {}, turboTasks: unknown) => {
startTrace: (options = {}, turboTasks: { __napi: 'TurboTasks' }) => {
initHeapProfiler()
return (customBindings ?? bindings).runTurboTracing(
toBuffer({ exact: true, ...options }),
turboTasks
)
},
createTurboTasks: (memoryLimit?: number): unknown =>
bindings.createTurboTasks(memoryLimit),
createTurboTasks: (
outputPath: string,
memoryLimit?: number
): { __napi: 'TurboTasks' } =>
bindings.createTurboTasks(outputPath, memoryLimit),
entrypoints: {
stream: (
turboTasks: any,
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/dev/hot-reloader-turbopack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export async function createHotReloaderTurbopack(
{
projectPath: dir,
rootPath: opts.nextConfig.outputFileTracingRoot || dir,
distDir,
nextConfig: opts.nextConfig,
jsConfig: await getTurbopackJsConfig(dir, nextConfig),
watch: true,
Expand Down
Loading
Loading