diff --git a/turbopack/crates/turbopack-cli/Cargo.toml b/turbopack/crates/turbopack-cli/Cargo.toml index 6b1aa163e7dfa..3558ab9e56677 100644 --- a/turbopack/crates/turbopack-cli/Cargo.toml +++ b/turbopack/crates/turbopack-cli/Cargo.toml @@ -42,6 +42,7 @@ mime = { workspace = true } owo-colors = { workspace = true } serde = { workspace = true } tokio = { workspace = true, features = ["full"] } +tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } turbo-rcstr = { workspace = true } turbo-tasks = { workspace = true } diff --git a/turbopack/crates/turbopack-cli/src/build/mod.rs b/turbopack/crates/turbopack-cli/src/build/mod.rs index 6c1bb9173ca59..0eaf486ad4e4c 100644 --- a/turbopack/crates/turbopack-cli/src/build/mod.rs +++ b/turbopack/crates/turbopack-cli/src/build/mod.rs @@ -7,6 +7,7 @@ use std::{ }; use anyhow::{bail, Context, Result}; +use tracing::Instrument; use turbo_rcstr::RcStr; use turbo_tasks::{ apply_effects, ReadConsistency, ResolvedVc, TransientInstance, TryJoinIterExt, TurboTasks, @@ -146,7 +147,9 @@ impl TurbopackBuildBuilder { // Await the result to propagate any errors. build_result_op.read_strongly_consistent().await?; - apply_effects(build_result_op).await?; + apply_effects(build_result_op) + .instrument(tracing::info_span!("apply effects")) + .await?; let issue_reporter: Vc> = Vc::upcast(ConsoleUi::new(TransientInstance::new(LogOptions { @@ -267,28 +270,38 @@ async fn build_internal( let origin = PlainResolveOrigin::new(asset_context, project_fs.root().join("_".into())); let project_dir = &project_dir; - let entries = entry_requests - .into_iter() - .map(|request_vc| async move { - let ty = Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)); - let request = request_vc.await?; - origin - .resolve_asset(request_vc, origin.resolve_options(ty.clone()), ty) - .await? - .first_module() - .await? - .with_context(|| { - format!( - "Unable to resolve entry {} from directory {}.", - request.request().unwrap(), - project_dir - ) - }) - }) - .try_join() - .await?; + let entries = async move { + entry_requests + .into_iter() + .map(|request_vc| async move { + let ty = Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)); + let request = request_vc.await?; + origin + .resolve_asset(request_vc, origin.resolve_options(ty.clone()), ty) + .await? + .first_module() + .await? + .with_context(|| { + format!( + "Unable to resolve entry {} from directory {}.", + request.request().unwrap(), + project_dir + ) + }) + }) + .try_join() + .await + } + .instrument(tracing::info_span!("resolve entries")) + .await?; - let module_graph = ModuleGraph::from_modules(Vc::cell(entries.clone())); + let module_graph = async { + ModuleGraph::from_modules(Vc::cell(entries.clone())) + .resolve() + .await + } + .instrument(tracing::info_span!("prepare module graph")) + .await?; let module_id_strategy = ResolvedVc::upcast( get_global_module_id_strategy(module_graph) .to_resolved() @@ -372,16 +385,40 @@ async fn build_internal( let entry_chunk_groups = entries .into_iter() - .map(|entry_module| async move { - Ok( - if let Some(ecmascript) = - ResolvedVc::try_sidecast::>(entry_module).await? - { - match target { - Target::Browser => { - chunking_context - .evaluated_chunk_group( - AssetIdent::from_path( + .map(async |entry_module| { + async move { + Ok( + if let Some(ecmascript) = + ResolvedVc::try_sidecast::>(entry_module).await? + { + match target { + Target::Browser => { + chunking_context + .evaluated_chunk_group( + AssetIdent::from_path( + build_output_root + .join( + ecmascript + .ident() + .path() + .file_stem() + .await? + .as_deref() + .unwrap() + .into(), + ) + .with_extension("entry.js".into()), + ), + EvaluatableAssets::one(*ResolvedVc::upcast(ecmascript)), + module_graph, + Value::new(AvailabilityInfo::Root), + ) + .await? + .assets + } + Target::Node => ResolvedVc::cell(vec![ + chunking_context + .entry_chunk_group( build_output_root .join( ecmascript @@ -394,58 +431,46 @@ async fn build_internal( .into(), ) .with_extension("entry.js".into()), - ), - EvaluatableAssets::one(*ResolvedVc::upcast(ecmascript)), - module_graph, - Value::new(AvailabilityInfo::Root), - ) - .await? - .assets + *ResolvedVc::upcast(ecmascript), + EvaluatableAssets::one(*ResolvedVc::upcast(ecmascript)), + module_graph, + OutputAssets::empty(), + Value::new(AvailabilityInfo::Root), + ) + .await? + .asset, + ]), } - Target::Node => ResolvedVc::cell(vec![ - chunking_context - .entry_chunk_group( - build_output_root - .join( - ecmascript - .ident() - .path() - .file_stem() - .await? - .as_deref() - .unwrap() - .into(), - ) - .with_extension("entry.js".into()), - *ResolvedVc::upcast(ecmascript), - EvaluatableAssets::one(*ResolvedVc::upcast(ecmascript)), - module_graph, - OutputAssets::empty(), - Value::new(AvailabilityInfo::Root), - ) - .await? - .asset, - ]), - } - } else { - bail!( - "Entry module is not chunkable, so it can't be used to bootstrap the \ - application" - ) - }, - ) + } else { + bail!( + "Entry module is not chunkable, so it can't be used to bootstrap the \ + application" + ) + }, + ) + } + .instrument(tracing::info_span!("chunk entry")) + .await }) .try_join() .await?; let mut chunks: HashSet>> = HashSet::new(); for chunk_group in entry_chunk_groups { - chunks.extend(&*all_assets_from_entries(*chunk_group).await?); + chunks.extend( + &*async move { all_assets_from_entries(*chunk_group).await } + .instrument(tracing::info_span!("list chunks")) + .await?, + ); } chunks .iter() - .map(|c| c.content().write(c.ident().path())) + .map(async |c| { + async move { c.content().write(c.ident().path()).resolve().await } + .instrument(tracing::info_span!("build chunk content")) + .await + }) .try_join() .await?; diff --git a/turbopack/crates/turbopack-cli/src/lib.rs b/turbopack/crates/turbopack-cli/src/lib.rs index 76c66cbde1a58..6f45f43561a7d 100644 --- a/turbopack/crates/turbopack-cli/src/lib.rs +++ b/turbopack/crates/turbopack-cli/src/lib.rs @@ -2,6 +2,7 @@ #![feature(min_specialization)] #![feature(arbitrary_self_types)] #![feature(arbitrary_self_types_pointers)] +#![feature(async_closure)] pub mod arguments; pub mod build; diff --git a/turbopack/crates/turbopack-ecmascript/src/minify.rs b/turbopack/crates/turbopack-ecmascript/src/minify.rs index 571f14c224b77..5ddc7418cf56f 100644 --- a/turbopack/crates/turbopack-ecmascript/src/minify.rs +++ b/turbopack/crates/turbopack-ecmascript/src/minify.rs @@ -1,4 +1,4 @@ -use std::{io::Write, sync::Arc}; +use std::{borrow::Cow, io::Write, sync::Arc}; use anyhow::{bail, Context, Result}; use swc_core::{ @@ -19,7 +19,8 @@ use swc_core::{ transforms::base::fixer::paren_remover, }, }; -use turbo_tasks::{ResolvedVc, Vc}; +use tracing::{field::Empty, Instrument}; +use turbo_tasks::{ResolvedVc, ValueToString, Vc}; use turbo_tasks_fs::FileSystemPath; use turbopack_core::{ code_builder::{Code, CodeBuilder}, @@ -34,6 +35,22 @@ pub async fn minify( code: Vc, source_maps: Vc, ) -> Result> { + let code_ref = code.await?; + let code_str = code_ref.source_code().to_str()?; + let span = tracing::info_span!("minify", path = %path.to_string().await?, input_len = code_str.len(), output_len = Empty); + let code = async move { minify_inner(path, code, code_str, source_maps).await } + .instrument(span.clone()) + .await?; + span.record("output_len", code.source_code().len()); + Ok(code.cell()) +} + +pub async fn minify_inner( + path: Vc, + code: Vc, + code_str: Cow<'_, str>, + source_maps: Vc, +) -> Result { let path = path.await?; let source_maps = source_maps.await?.then(|| code.generate_source_map()); let code = code.await?; @@ -43,7 +60,7 @@ pub async fn minify( let compiler = Arc::new(Compiler::new(cm.clone())); let fm = compiler.cm.new_source_file( FileName::Custom(path.path.to_string()).into(), - code.source_code().to_str()?.into_owned(), + code_str.into_owned(), ); let lexer = Lexer::new( @@ -134,7 +151,7 @@ pub async fn minify( } else { builder.push_source(&src.into(), None); } - Ok(builder.build().cell()) + Ok(builder.build()) } // From https://github.com/swc-project/swc/blob/11efd4e7c5e8081f8af141099d3459c3534c1e1d/crates/swc/src/lib.rs#L523-L560