From aa2e21fe462976197bf669e99c2d7b7022a2b398 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 7 Apr 2026 15:14:46 +0800 Subject: [PATCH] feat(turbopack): wasm file write support and available_parallelism for worker pool - turbo-tasks-fs: add wasm32-specific file write/remove via wasm_fs_offload - turbopack-node: extract available_parallelism module for cross-platform concurrency - turbopack-node: use available_parallelism() directly in evaluate pool setup --- turbopack/crates/turbo-tasks-fs/src/lib.rs | 32 +++++++++++++++++++ .../crates/turbopack-node/src/evaluate.rs | 8 ++--- turbopack/crates/turbopack-node/src/lib.rs | 1 + 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/turbopack/crates/turbo-tasks-fs/src/lib.rs b/turbopack/crates/turbo-tasks-fs/src/lib.rs index 4d574cc0a652..c3e4d8d363e0 100644 --- a/turbopack/crates/turbo-tasks-fs/src/lib.rs +++ b/turbopack/crates/turbo-tasks-fs/src/lib.rs @@ -1115,6 +1115,7 @@ impl FileSystem for DiskFileSystem { return Ok(()); } + #[cfg(not(all(target_family = "wasm", target_os = "unknown")))] match &*self.content { FileContent::Content(..) => { let create_directory = compare == FileComparison::Create; @@ -1181,6 +1182,37 @@ impl FileSystem for DiskFileSystem { } } + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + match &*self.content { + FileContent::Content(..) => { + let create_directory = compare == FileComparison::Create; + if create_directory && let Some(parent) = full_path.parent() { + self.inner.create_directory(parent).await.with_context(|| { + format!( + "failed to create directory {parent:?} for write to \ + {full_path:?}", + ) + })?; + } + let content = self.content.clone(); + let FileContent::Content(file) = &*content else { + unreachable!() + }; + wasm_fs_offload::CLIENT + .write(&full_path, file.content().to_bytes()) + .instrument(tracing::info_span!("write file", name = ?full_path)) + .await + .with_context(|| format!("failed to write to {full_path:?}"))?; + } + FileContent::NotFound => { + wasm_fs_offload::CLIENT + .remove_file(&full_path) + .instrument(tracing::info_span!("remove file", name = ?full_path)) + .await + .with_context(|| format!("removing {full_path:?} failed"))?; + } + } + self.inner .invalidate_from_write(&full_path, old_invalidators); diff --git a/turbopack/crates/turbopack-node/src/evaluate.rs b/turbopack/crates/turbopack-node/src/evaluate.rs index c5f6e4f50039..5fe066afde42 100644 --- a/turbopack/crates/turbopack-node/src/evaluate.rs +++ b/turbopack/crates/turbopack-node/src/evaluate.rs @@ -1,7 +1,4 @@ -use std::{ - borrow::Cow, iter, process::ExitStatus, sync::Arc, thread::available_parallelism, - time::Duration, -}; +use std::{borrow::Cow, iter, process::ExitStatus, sync::Arc, time::Duration}; use anyhow::{Result, bail}; use bincode::{Decode, Encode}; @@ -45,6 +42,7 @@ use crate::process_pool::ChildProcessPool; use crate::worker_pool::WorkerThreadPool; use crate::{ AssetsForSourceMapping, + available_parallelism::available_parallelism, backend::{CreatePoolOptions, NodeBackend}, embed_js::embed_file_path, emit, emit_package_json, @@ -275,7 +273,7 @@ pub async fn get_evaluate_pool( assets_for_source_mapping, assets_root: output_root.clone(), project_dir: chunking_context.root_path().owned().await?, - concurrency: available_parallelism().map_or(1, |v| v.get()), + concurrency: available_parallelism(), debug, }) .await?; diff --git a/turbopack/crates/turbopack-node/src/lib.rs b/turbopack/crates/turbopack-node/src/lib.rs index bead5baf633e..90ca3d268cc8 100644 --- a/turbopack/crates/turbopack-node/src/lib.rs +++ b/turbopack/crates/turbopack-node/src/lib.rs @@ -13,6 +13,7 @@ use turbopack_core::{ virtual_output::VirtualOutputAsset, }; +mod available_parallelism; mod backend; pub mod debug; pub mod embed_js;