diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2024-06-05 11:04:16 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-05 17:04:16 +0200 |
commit | 7ed90a20d04982ae15a52ae2378cbffd4b6839df (patch) | |
tree | 3297d6f7227fbf1cf80e17a2a376ef4dfa52e6ad /cli/resolver.rs | |
parent | 0544d60012006b1c7799d8b6eafacec9567901ad (diff) |
fix: better handling of npm resolution occurring on workers (#24094)
Closes https://github.com/denoland/deno/issues/24063
Diffstat (limited to 'cli/resolver.rs')
-rw-r--r-- | cli/resolver.rs | 113 |
1 files changed, 84 insertions, 29 deletions
diff --git a/cli/resolver.rs b/cli/resolver.rs index 8fbacd8f1..a28dfce91 100644 --- a/cli/resolver.rs +++ b/cli/resolver.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use async_trait::async_trait; use dashmap::DashMap; use dashmap::DashSet; use deno_ast::MediaType; @@ -9,15 +10,15 @@ use deno_core::error::AnyError; use deno_core::futures::future; use deno_core::futures::future::LocalBoxFuture; use deno_core::futures::FutureExt; -use deno_core::ModuleCodeString; +use deno_core::ModuleSourceCode; use deno_core::ModuleSpecifier; -use deno_graph::source::NpmPackageReqResolution; -use deno_graph::source::NpmResolver; use deno_graph::source::ResolutionMode; use deno_graph::source::ResolveError; use deno_graph::source::Resolver; use deno_graph::source::UnknownBuiltInNodeModuleError; use deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE; +use deno_graph::NpmPackageReqsResolution; +use deno_npm::registry::NpmPackageInfo; use deno_runtime::deno_fs; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node::is_builtin_node_module; @@ -34,6 +35,8 @@ use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageReq; use import_map::ImportMap; use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::HashMap; use std::path::Path; use std::path::PathBuf; use std::rc::Rc; @@ -60,7 +63,7 @@ pub fn format_range_with_colors(range: &deno_graph::Range) -> String { } pub struct ModuleCodeStringSource { - pub code: ModuleCodeString, + pub code: ModuleSourceCode, pub found_url: ModuleSpecifier, pub media_type: MediaType, } @@ -293,7 +296,7 @@ impl NpmModuleLoader { let file_path = specifier.to_file_path().unwrap(); let code = self .fs - .read_text_file_async(file_path.clone(), None) + .read_file_async(file_path.clone(), None) .await .map_err(AnyError::from) .with_context(|| { @@ -329,16 +332,20 @@ impl NpmModuleLoader { let code = if self.cjs_resolutions.contains(specifier) { // translate cjs to esm if it's cjs and inject node globals - self - .node_code_translator - .translate_cjs_to_esm(specifier, Some(code), permissions) - .await? + let code = String::from_utf8(code)?; + ModuleSourceCode::String( + self + .node_code_translator + .translate_cjs_to_esm(specifier, Some(code), permissions) + .await? + .into(), + ) } else { // esm and json code is untouched - code + ModuleSourceCode::Bytes(code.into_boxed_slice().into()) }; Ok(ModuleCodeStringSource { - code: code.into(), + code, found_url: specifier.clone(), media_type: MediaType::from_specifier(specifier), }) @@ -498,8 +505,12 @@ impl CliGraphResolver { self } - pub fn as_graph_npm_resolver(&self) -> &dyn NpmResolver { - self + pub fn create_graph_npm_resolver(&self) -> WorkerCliNpmGraphResolver { + WorkerCliNpmGraphResolver { + npm_resolver: self.npm_resolver.as_ref(), + memory_cache: Default::default(), + bare_node_builtins_enabled: self.bare_node_builtins_enabled, + } } pub fn found_package_json_dep(&self) -> bool { @@ -782,7 +793,17 @@ fn resolve_package_json_dep( Ok(None) } -impl NpmResolver for CliGraphResolver { +#[derive(Debug)] +pub struct WorkerCliNpmGraphResolver<'a> { + npm_resolver: Option<&'a Arc<dyn CliNpmResolver>>, + // use a cache per worker so that another worker doesn't clear the + // cache of another worker + memory_cache: Rc<RefCell<HashMap<String, Arc<NpmPackageInfo>>>>, + bare_node_builtins_enabled: bool, +} + +#[async_trait(?Send)] +impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> { fn resolve_builtin_node_module( &self, specifier: &ModuleSpecifier, @@ -818,17 +839,20 @@ impl NpmResolver for CliGraphResolver { &self, package_name: &str, ) -> LocalBoxFuture<'static, Result<(), AnyError>> { - match &self.npm_resolver { + match self.npm_resolver { Some(npm_resolver) if npm_resolver.as_managed().is_some() => { - let package_name = package_name.to_string(); let npm_resolver = npm_resolver.clone(); + let package_name = package_name.to_string(); + let memory_cache = self.memory_cache.clone(); async move { if let Some(managed) = npm_resolver.as_managed() { - managed.cache_package_info(&package_name).await?; + let package_info = + managed.cache_package_info(&package_name).await?; + memory_cache.borrow_mut().insert(package_name, package_info); } Ok(()) } - .boxed() + .boxed_local() } _ => { // return it succeeded and error at the import site below @@ -837,19 +861,50 @@ impl NpmResolver for CliGraphResolver { } } - fn resolve_npm(&self, package_req: &PackageReq) -> NpmPackageReqResolution { + async fn resolve_pkg_reqs( + &self, + package_reqs: &[&PackageReq], + ) -> NpmPackageReqsResolution { match &self.npm_resolver { - Some(npm_resolver) => match npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(npm_resolver) => { - npm_resolver.resolve_npm_for_deno_graph(package_req) + Some(npm_resolver) => { + let npm_resolver = match npm_resolver.as_inner() { + InnerCliNpmResolverRef::Managed(npm_resolver) => npm_resolver, + // if we are using byonm, then this should never be called because + // we don't use deno_graph's npm resolution in this case + InnerCliNpmResolverRef::Byonm(_) => unreachable!(), + }; + + let reqs_with_package_infos = { + let memory_cache = self.memory_cache.borrow(); + package_reqs + .iter() + .map(|package_req| { + let package_info = memory_cache + .get(&package_req.name) + .unwrap() // ok because deno_graph would have called load_and_cache_npm_package_info + .clone(); + (*package_req, package_info) + }) + .collect::<Vec<_>>() + }; + let result = npm_resolver + .resolve_npm_for_deno_graph(&reqs_with_package_infos) + .await; + if matches!(result, NpmPackageReqsResolution::ReloadRegistryInfo) { + self.memory_cache.borrow_mut().clear(); } - // if we are using byonm, then this should never be called because - // we don't use deno_graph's npm resolution in this case - InnerCliNpmResolverRef::Byonm(_) => unreachable!(), - }, - None => NpmPackageReqResolution::Err(anyhow!( - "npm specifiers were requested; but --no-npm is specified" - )), + result + } + None => NpmPackageReqsResolution::Resolutions( + package_reqs + .iter() + .map(|_| { + Err(Arc::new(anyhow!( + "npm specifiers were requested; but --no-npm is specified" + ))) + }) + .collect(), + ), } } |