From 253c785272768505758dff2d3e33ad34a5da2e9d Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 14 Feb 2024 16:22:48 +0100 Subject: [PATCH] dedupe resolving independent on reference type (#7349) ### Description * dedupe resolving independent on reference type * add more tracing to resolving steps ### Testing Instructions Closes PACK-2464 --- crates/turbopack-core/src/resolve/mod.rs | 458 ++++++++++++----------- 1 file changed, 238 insertions(+), 220 deletions(-) diff --git a/crates/turbopack-core/src/resolve/mod.rs b/crates/turbopack-core/src/resolve/mod.rs index 89d573d307416..35796c79d76f6 100644 --- a/crates/turbopack-core/src/resolve/mod.rs +++ b/crates/turbopack-core/src/resolve/mod.rs @@ -1255,6 +1255,15 @@ pub async fn resolve( reference_type: Value, request: Vc, options: Vc, +) -> Result> { + resolve_inline(lookup_path, reference_type.into_value(), request, options).await +} + +pub async fn resolve_inline( + lookup_path: Vc, + reference_type: ReferenceType, + request: Vc, + options: Vc, ) -> Result> { let span = { let lookup_path = lookup_path.to_string().await?; @@ -1263,17 +1272,21 @@ pub async fn resolve( "resolving", lookup_path = *lookup_path, request = *request, - reference_type = display(&*reference_type) + reference_type = display(&reference_type), ) }; async { - let raw_result = resolve_internal_inline(lookup_path, request, options) - .await? + let raw_result = resolve_internal(lookup_path, request, options) .resolve() .await?; - let result = - handle_resolve_plugins(lookup_path, reference_type, request, options, raw_result) - .await?; + let result = handle_resolve_plugins( + lookup_path, + Value::new(reference_type), + request, + options, + raw_result, + ) + .await?; Ok(result) } .instrument(span) @@ -1402,14 +1415,7 @@ async fn resolve_internal( request: Vc, options: Vc, ) -> Result> { - let span = { - let lookup_path = lookup_path.to_string().await?; - let request = request.to_string().await?; - tracing::info_span!("resolving", lookup_path = *lookup_path, request = *request) - }; - resolve_internal_inline(lookup_path, request, options) - .instrument(span) - .await + resolve_internal_inline(lookup_path, request, options).await } fn resolve_internal_boxed( @@ -1420,237 +1426,249 @@ fn resolve_internal_boxed( Box::pin(resolve_internal_inline(lookup_path, request, options)) } -#[tracing::instrument(level = Level::TRACE, skip_all)] async fn resolve_internal_inline( lookup_path: Vc, request: Vc, options: Vc, ) -> Result> { - // This explicit deref of `options` is necessary - #[allow(clippy::explicit_auto_deref)] - let options_value: &ResolveOptions = &*options.await?; - - // Apply import mappings if provided - if let Some(import_map) = &options_value.import_map { - let result = import_map.await?.lookup(lookup_path, request).await?; - if !matches!(result, ImportMapResult::NoEntry) { - let resolved_result = resolve_import_map_result( - &result, - lookup_path, - lookup_path, - request, - options, - request.query(), - ) - .await?; - // We might have matched an alias in the import map, but there is no guarantee - // the alias actually resolves to something. For instance, a tsconfig.json - // `compilerOptions.paths` option might alias "@*" to "./*", which - // would also match a request to "@emotion/core". Here, we follow what the - // Typescript resolution algorithm does in case an alias match - // doesn't resolve to anything: fall back to resolving the request normally. - if let Some(result) = resolved_result { - return Ok(result); + let span = { + let lookup_path = lookup_path.to_string().await?; + let request = request.to_string().await?; + tracing::info_span!( + "internal resolving", + lookup_path = *lookup_path, + request = *request + ) + }; + async move { + // This explicit deref of `options` is necessary + #[allow(clippy::explicit_auto_deref)] + let options_value: &ResolveOptions = &*options.await?; + + // Apply import mappings if provided + if let Some(import_map) = &options_value.import_map { + let result = import_map.await?.lookup(lookup_path, request).await?; + if !matches!(result, ImportMapResult::NoEntry) { + let resolved_result = resolve_import_map_result( + &result, + lookup_path, + lookup_path, + request, + options, + request.query(), + ) + .await?; + // We might have matched an alias in the import map, but there is no guarantee + // the alias actually resolves to something. For instance, a tsconfig.json + // `compilerOptions.paths` option might alias "@*" to "./*", which + // would also match a request to "@emotion/core". Here, we follow what the + // Typescript resolution algorithm does in case an alias match + // doesn't resolve to anything: fall back to resolving the request normally. + if let Some(result) = resolved_result { + return Ok(result); + } } } - } - let request_value = request.await?; - let result = match &*request_value { - Request::Dynamic => ResolveResult::unresolveable().into(), - Request::Alternatives { requests } => { - let results = requests - .iter() - .map(|req| resolve_internal_boxed(lookup_path, *req, options)) - .try_join() - .await?; + let request_value = request.await?; + let result = match &*request_value { + Request::Dynamic => ResolveResult::unresolveable().into(), + Request::Alternatives { requests } => { + let results = requests + .iter() + .map(|req| resolve_internal_boxed(lookup_path, *req, options)) + .try_join() + .await?; - merge_results(results) - } - Request::Raw { - path, - query, - force_in_lookup_dir, - } => { - let mut results = Vec::new(); - let matches = read_matches( - lookup_path, - "".to_string(), - *force_in_lookup_dir, - Pattern::new(path.clone()).resolve().await?, - ) - .await?; + merge_results(results) + } + Request::Raw { + path, + query, + force_in_lookup_dir, + } => { + let mut results = Vec::new(); + let matches = read_matches( + lookup_path, + "".to_string(), + *force_in_lookup_dir, + Pattern::new(path.clone()).resolve().await?, + ) + .await?; - for m in matches.iter() { - match m { - PatternMatch::File(matched_pattern, path) => { - results.push( - resolved( - RequestKey::new(matched_pattern.clone()), - *path, - lookup_path, - request, - options_value, - options, - *query, - ) - .await?, - ); - } - PatternMatch::Directory(_, path) => { - results.push(resolve_into_folder(*path, options, *query)); + for m in matches.iter() { + match m { + PatternMatch::File(matched_pattern, path) => { + results.push( + resolved( + RequestKey::new(matched_pattern.clone()), + *path, + lookup_path, + request, + options_value, + options, + *query, + ) + .await?, + ); + } + PatternMatch::Directory(_, path) => { + results.push(resolve_into_folder(*path, options, *query)); + } } } - } - merge_results(results) - } - Request::Relative { - path, - query, - force_in_lookup_dir, - } => { - resolve_relative_request( - lookup_path, - request, - options, - options_value, + merge_results(results) + } + Request::Relative { path, - *query, - *force_in_lookup_dir, - ) - .await? - } - Request::Module { - module, - path, - query, - } => { - resolve_module_request( - lookup_path, - request, - options, - options_value, + query, + force_in_lookup_dir, + } => { + resolve_relative_request( + lookup_path, + request, + options, + options_value, + path, + *query, + *force_in_lookup_dir, + ) + .await? + } + Request::Module { module, path, - *query, - ) - .await? - } - Request::ServerRelative { path, query } => { - let mut new_pat = path.clone(); - new_pat.push_front(".".to_string().into()); - let relative = Request::relative(Value::new(new_pat), *query, true); - - ResolvingIssue { - severity: IssueSeverity::Error.cell(), - request_type: "server relative import: not implemented yet".to_string(), - request, - file_path: lookup_path, - resolve_options: options, - error_message: Some( - "server relative imports are not implemented yet. Please try an import \ - relative to the file you are importing from." - .to_string(), - ), - source: None, + query, + } => { + resolve_module_request( + lookup_path, + request, + options, + options_value, + module, + path, + *query, + ) + .await? } - .cell() - .emit(); + Request::ServerRelative { path, query } => { + let mut new_pat = path.clone(); + new_pat.push_front(".".to_string().into()); + let relative = Request::relative(Value::new(new_pat), *query, true); - resolve_internal_boxed( - lookup_path.root().resolve().await?, - relative.resolve().await?, - options, - ) - .await? - } - Request::Windows { path: _, query: _ } => { - ResolvingIssue { - severity: IssueSeverity::Error.cell(), - request_type: "windows import: not implemented yet".to_string(), - request, - file_path: lookup_path, - resolve_options: options, - error_message: Some("windows imports are not implemented yet".to_string()), - source: None, + ResolvingIssue { + severity: IssueSeverity::Error.cell(), + request_type: "server relative import: not implemented yet".to_string(), + request, + file_path: lookup_path, + resolve_options: options, + error_message: Some( + "server relative imports are not implemented yet. Please try an import \ + relative to the file you are importing from." + .to_string(), + ), + source: None, + } + .cell() + .emit(); + + resolve_internal_boxed( + lookup_path.root().resolve().await?, + relative.resolve().await?, + options, + ) + .await? } - .cell() - .emit(); + Request::Windows { path: _, query: _ } => { + ResolvingIssue { + severity: IssueSeverity::Error.cell(), + request_type: "windows import: not implemented yet".to_string(), + request, + file_path: lookup_path, + resolve_options: options, + error_message: Some("windows imports are not implemented yet".to_string()), + source: None, + } + .cell() + .emit(); - ResolveResult::unresolveable().into() - } - Request::Empty => ResolveResult::unresolveable().into(), - Request::PackageInternal { path } => { - let options_value = options.await?; - let (conditions, unspecified_conditions) = options_value - .in_package - .iter() - .find_map(|item| match item { - ResolveInPackage::ImportsField { - conditions, - unspecified_conditions, - } => Some((Cow::Borrowed(conditions), *unspecified_conditions)), - _ => None, - }) - .unwrap_or_else(|| (Default::default(), ConditionValue::Unset)); - resolve_package_internal_with_imports_field( - lookup_path, - request, - options, - path, - &conditions, - &unspecified_conditions, - ) - .await? - } - Request::Uri { - protocol, - remainder, - } => { - let uri = format!("{}{}", protocol, remainder); - ResolveResult::primary_with_key( - RequestKey::new(uri.clone()), - ResolveResultItem::OriginalReferenceTypeExternal(uri), - ) - .into() - } - Request::Unknown { path } => { - ResolvingIssue { - severity: IssueSeverity::Error.cell(), - request_type: format!("unknown import: `{}`", path), - request, - file_path: lookup_path, - resolve_options: options, - error_message: None, - source: None, + ResolveResult::unresolveable().into() } - .cell() - .emit(); - ResolveResult::unresolveable().into() - } - }; + Request::Empty => ResolveResult::unresolveable().into(), + Request::PackageInternal { path } => { + let options_value = options.await?; + let (conditions, unspecified_conditions) = options_value + .in_package + .iter() + .find_map(|item| match item { + ResolveInPackage::ImportsField { + conditions, + unspecified_conditions, + } => Some((Cow::Borrowed(conditions), *unspecified_conditions)), + _ => None, + }) + .unwrap_or_else(|| (Default::default(), ConditionValue::Unset)); + resolve_package_internal_with_imports_field( + lookup_path, + request, + options, + path, + &conditions, + &unspecified_conditions, + ) + .await? + } + Request::Uri { + protocol, + remainder, + } => { + let uri = format!("{}{}", protocol, remainder); + ResolveResult::primary_with_key( + RequestKey::new(uri.clone()), + ResolveResultItem::OriginalReferenceTypeExternal(uri), + ) + .into() + } + Request::Unknown { path } => { + ResolvingIssue { + severity: IssueSeverity::Error.cell(), + request_type: format!("unknown import: `{}`", path), + request, + file_path: lookup_path, + resolve_options: options, + error_message: None, + source: None, + } + .cell() + .emit(); + ResolveResult::unresolveable().into() + } + }; - // Apply fallback import mappings if provided - if let Some(import_map) = &options_value.fallback_import_map { - if *result.is_unresolveable().await? { - let result = import_map.await?.lookup(lookup_path, request).await?; - let resolved_result = resolve_import_map_result( - &result, - lookup_path, - lookup_path, - request, - options, - request.query(), - ) - .await?; - if let Some(result) = resolved_result { - return Ok(result); + // Apply fallback import mappings if provided + if let Some(import_map) = &options_value.fallback_import_map { + if *result.is_unresolveable().await? { + let result = import_map.await?.lookup(lookup_path, request).await?; + let resolved_result = resolve_import_map_result( + &result, + lookup_path, + lookup_path, + request, + options, + request.query(), + ) + .await?; + if let Some(result) = resolved_result { + return Ok(result); + } } } - } - Ok(result) + Ok(result) + } + .instrument(span) + .await } #[turbo_tasks::function]