mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
### What? Changes the `root` parameter of `DiskFileSystem::new`, `DiskFileSystem::new_with_denied_paths`, and the internal `DiskFileSystem::new_internal` from `RcStr` to `Vc<RcStr>`. ### Why? Part of the effort to make the Turbopack persistent cache portable when the absolute path of the project directory changes. By accepting the root as a `Vc<RcStr>` instead of a plain `RcStr`, the path is tracked as a turbo-tasks value. This allows the cache to remain valid even when the project root moves (e.g. on a different machine, a different CI working directory, or a relocated checkout), since the value can be substituted independently without invalidating unrelated cached computations. ### How? - `new_internal` is now an `async fn` that awaits the `Vc<RcStr>` to extract the underlying `RcStr` for constructing `DiskFileSystemInner`. It returns `Result<Vc<Self>>` accordingly. - `new` and `new_with_denied_paths` (the public constructors, which are not `#[turbo_tasks::function]` themselves) are updated to accept `Vc<RcStr>` and forward it to `new_internal`. - All 23 call sites across the codebase are updated to wrap their root string with `Vc::cell(...)` before passing it. Verified with `cargo clippy --all-targets` (clean), `cargo test -p turbo-tasks-backend` (all pass), and `cargo test -p turbopack-tests` (all 89 pass). <!-- NEXT_JS_LLM_PR --> --------- Co-authored-by: Tobias Koppers <[email protected]> Co-authored-by: Claude <[email protected]>
145 lines
5.2 KiB
Rust
145 lines
5.2 KiB
Rust
use std::{fs, path::PathBuf};
|
|
|
|
use criterion::{Bencher, BenchmarkId, Criterion};
|
|
use regex::Regex;
|
|
use turbo_rcstr::{RcStr, rcstr};
|
|
use turbo_tasks::{Effects, OperationVc, TurboTasks, Vc, take_effects};
|
|
use turbo_tasks_backend::{BackendOptions, TurboTasksBackend, noop_backing_storage};
|
|
use turbo_tasks_fs::{DiskFileSystem, FileSystem, NullFileSystem};
|
|
use turbopack::{
|
|
ModuleAssetContext, emit_assets_into_dir_operation,
|
|
module_options::{EcmascriptOptionsContext, ModuleOptionsContext},
|
|
};
|
|
use turbopack_core::{
|
|
compile_time_info::CompileTimeInfo,
|
|
context::AssetContext,
|
|
environment::{Environment, ExecutionEnvironment, NodeJsEnvironment},
|
|
file_source::FileSource,
|
|
ident::Layer,
|
|
rebase::RebasedAsset,
|
|
reference::all_assets_from_entry,
|
|
reference_type::ReferenceType,
|
|
};
|
|
use turbopack_resolve::resolve_options_context::ResolveOptionsContext;
|
|
|
|
#[turbo_tasks::function(operation)]
|
|
async fn extract_effects_operation(op: OperationVc<()>) -> anyhow::Result<Vc<Effects>> {
|
|
let _ = op.resolve().strongly_consistent().await?;
|
|
Ok(take_effects(op).await?.cell())
|
|
}
|
|
|
|
// TODO this should move to the `node-file-trace` crate
|
|
pub fn benchmark(c: &mut Criterion) {
|
|
let bench_filter = Regex::new(r"(empty|simple|dynamic-in-package|react|whatwg-url|axios|azure-cosmos|cowsay|env-var|fast-glob)\.js$").unwrap();
|
|
|
|
let tests_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests");
|
|
let tests_dir = tests_root.join("node-file-trace/integration");
|
|
|
|
let mut group = c.benchmark_group("node-file-trace");
|
|
group.sample_size(10);
|
|
|
|
let results = fs::read_dir(tests_dir).unwrap();
|
|
for result in results {
|
|
let entry = result.unwrap();
|
|
if entry.file_type().unwrap().is_file() {
|
|
let name = entry.file_name().into_string().unwrap();
|
|
if !bench_filter.is_match(&name) {
|
|
continue;
|
|
}
|
|
|
|
let input = format!("node-file-trace/integration/{name}");
|
|
let tests_root = tests_root.to_string_lossy().to_string();
|
|
|
|
let bench_input = BenchInput { tests_root, input };
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("emit", &bench_input.input),
|
|
&bench_input,
|
|
bench_emit,
|
|
);
|
|
}
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
struct BenchInput {
|
|
tests_root: String,
|
|
input: String,
|
|
}
|
|
|
|
fn bench_emit(b: &mut Bencher, bench_input: &BenchInput) {
|
|
let rt = tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap();
|
|
|
|
b.to_async(rt).iter(move || {
|
|
let tt = TurboTasks::new(TurboTasksBackend::new(
|
|
BackendOptions::default(),
|
|
noop_backing_storage(),
|
|
));
|
|
let tests_root: RcStr = bench_input.tests_root.clone().into();
|
|
let input: RcStr = bench_input.input.clone().into();
|
|
async move {
|
|
tt.run_once(async move {
|
|
let input_fs = DiskFileSystem::new(rcstr!("tests"), Vc::cell(tests_root.clone()));
|
|
let input = input_fs.root().await?.join(&input)?;
|
|
|
|
let input_dir = input.parent().parent();
|
|
let output_fs: Vc<NullFileSystem> = NullFileSystem.cell();
|
|
let output_dir = output_fs.root().owned().await?;
|
|
|
|
let source = FileSource::new(input);
|
|
let compile_time_info = CompileTimeInfo::builder(
|
|
Environment::new(ExecutionEnvironment::NodeJsLambda(
|
|
NodeJsEnvironment::default().resolved_cell(),
|
|
))
|
|
.to_resolved()
|
|
.await?,
|
|
)
|
|
.cell()
|
|
.await?;
|
|
let module_asset_context = ModuleAssetContext::new(
|
|
Default::default(),
|
|
compile_time_info,
|
|
ModuleOptionsContext {
|
|
ecmascript: EcmascriptOptionsContext {
|
|
enable_types: true,
|
|
..Default::default()
|
|
},
|
|
..Default::default()
|
|
}
|
|
.cell(),
|
|
ResolveOptionsContext {
|
|
emulate_environment: Some(
|
|
compile_time_info.environment().to_resolved().await?,
|
|
),
|
|
collect_affecting_sources: true,
|
|
..Default::default()
|
|
}
|
|
.cell(),
|
|
Layer::new(rcstr!("node_file_trace")),
|
|
);
|
|
let module = module_asset_context
|
|
.process(Vc::upcast(source), ReferenceType::Undefined)
|
|
.module();
|
|
let rebased = RebasedAsset::new(module, input_dir, output_dir.clone());
|
|
let assets = all_assets_from_entry(Vc::upcast(rebased))
|
|
.to_resolved()
|
|
.await?;
|
|
|
|
extract_effects_operation(emit_assets_into_dir_operation(assets, output_dir))
|
|
.read_strongly_consistent()
|
|
.await?
|
|
.apply()
|
|
.await?;
|
|
|
|
Ok(())
|
|
})
|
|
.await
|
|
.unwrap();
|
|
}
|
|
})
|
|
}
|