0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 17:34:47 -05:00

perf: node resolution cache (#27838)

This adds a cache for node resolution, which makes repeat lookups about
15x faster.
This commit is contained in:
David Sherret 2025-02-03 20:25:10 -05:00 committed by GitHub
parent 073caf5fe9
commit 61faa32920
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 261 additions and 29 deletions

View file

@ -48,6 +48,7 @@ use deno_runtime::deno_web::BlobStore;
use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
use node_resolver::analyze::NodeCodeTranslator;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use once_cell::sync::OnceCell;
use sys_traits::EnvCurrentDir;
@ -644,6 +645,7 @@ impl CliFactory {
self.workspace_factory()?.clone(),
ResolverFactoryOptions {
conditions_from_resolution_mode: Default::default(),
node_resolution_cache: Some(Arc::new(NodeResolutionThreadLocalCache)),
no_sloppy_imports_cache: false,
npm_system_info: self.flags.subcommand.npm_system_info(),
specified_import_map: Some(Box::new(CliSpecifiedImportMapProvider {

View file

@ -33,6 +33,7 @@ use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use indexmap::IndexSet;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
use tower_lsp::lsp_types as lsp;
@ -897,6 +898,7 @@ impl FileSystemDocuments {
}
};
if dirty {
NodeResolutionThreadLocalCache::clear();
// attempt to update the file on the file system
self.refresh_document(specifier, resolver, config, cache, file_referrer)
} else {
@ -1375,6 +1377,7 @@ impl Documents {
self.resolver = resolver.clone();
node_resolver::PackageJsonThreadLocalCache::clear();
NodeResolutionThreadLocalCache::clear();
{
let fs_docs = &self.file_system_docs;
@ -1440,6 +1443,7 @@ impl Documents {
if !is_fs_docs_dirty && !self.dirty {
return;
}
NodeResolutionThreadLocalCache::clear();
let mut visit_doc = |doc: &Arc<Document>| {
let scope = doc.scope();
let dep_info = dep_info_by_scope.entry(scope.cloned()).or_default();

View file

@ -36,6 +36,8 @@ use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use node_resolver::NodeResolutionKind;
use node_resolver::PackageJsonThreadLocalCache;
@ -259,7 +261,7 @@ impl LspScopeResolver {
root_node_modules_dir: byonm_npm_resolver
.root_node_modules_path()
.map(|p| p.to_path_buf()),
sys: factory.sys.clone(),
sys: factory.node_resolution_sys.clone(),
pkg_json_resolver: self.pkg_json_resolver.clone(),
},
)
@ -673,6 +675,7 @@ struct ResolverFactoryServices {
struct ResolverFactory<'a> {
config_data: Option<&'a Arc<ConfigData>>,
pkg_json_resolver: Arc<CliPackageJsonResolver>,
node_resolution_sys: NodeResolutionSys<CliSys>,
sys: CliSys,
services: ResolverFactoryServices,
}
@ -688,6 +691,10 @@ impl<'a> ResolverFactory<'a> {
Self {
config_data,
pkg_json_resolver,
node_resolution_sys: NodeResolutionSys::new(
sys.clone(),
Some(Arc::new(NodeResolutionThreadLocalCache)),
),
sys,
services: Default::default(),
}
@ -706,7 +713,7 @@ impl<'a> ResolverFactory<'a> {
let sys = CliSys::default();
let options = if enable_byonm {
CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions {
sys: self.sys.clone(),
sys: self.node_resolution_sys.clone(),
pkg_json_resolver: self.pkg_json_resolver.clone(),
root_node_modules_dir: self.config_data.and_then(|config_data| {
config_data.node_modules_dir.clone().or_else(|| {
@ -933,7 +940,7 @@ impl<'a> ResolverFactory<'a> {
DenoIsBuiltInNodeModuleChecker,
npm_resolver.clone(),
self.pkg_json_resolver.clone(),
self.sys.clone(),
self.node_resolution_sys.clone(),
node_resolver::ConditionsFromResolutionMode::default(),
)))
})

View file

@ -49,6 +49,7 @@ use indexmap::IndexMap;
use indexmap::IndexSet;
use lazy_regex::lazy_regex;
use log::error;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use node_resolver::ResolutionMode;
use once_cell::sync::Lazy;
use regex::Captures;
@ -4600,6 +4601,9 @@ async fn op_poll_requests(
state.pending_requests.take().unwrap()
};
// clear the resolution cache after each request
NodeResolutionThreadLocalCache::clear();
let Some((request, scope, snapshot, response_tx, token, change)) =
pending_requests.recv().await
else {

View file

@ -76,6 +76,7 @@ use deno_runtime::WorkerExecutionMode;
use deno_runtime::WorkerLogLevel;
use deno_semver::npm::NpmPackageReqReference;
use node_resolver::analyze::NodeCodeTranslator;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use node_resolver::NodeResolutionKind;
@ -707,6 +708,7 @@ pub async fn run(
};
NpmRegistryReadPermissionChecker::new(sys.clone(), mode)
};
let node_resolution_sys = NodeResolutionSys::new(sys.clone(), None);
let (in_npm_pkg_checker, npm_resolver) = match metadata.node_modules {
Some(NodeModules::Managed { node_modules_dir }) => {
// create an npmrc that uses the fake npm_registry_url to resolve packages
@ -756,7 +758,7 @@ pub async fn run(
DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Byonm);
let npm_resolver = NpmResolver::<DenoRtSys>::new::<DenoRtSys>(
NpmResolverCreateOptions::Byonm(ByonmNpmResolverCreateOptions {
sys: sys.clone(),
sys: node_resolution_sys.clone(),
pkg_json_resolver: pkg_json_resolver.clone(),
root_node_modules_dir,
}),
@ -800,7 +802,7 @@ pub async fn run(
DenoIsBuiltInNodeModuleChecker,
npm_resolver.clone(),
pkg_json_resolver.clone(),
sys.clone(),
node_resolution_sys,
node_resolver::ConditionsFromResolutionMode::default(),
));
let cjs_tracker = Arc::new(CjsTracker::new(

View file

@ -18,6 +18,7 @@ use deno_package_json::PackageJsonRc;
use deno_path_util::normalize_path;
use deno_path_util::url_from_file_path;
use deno_path_util::url_to_file_path;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::InNpmPackageChecker;
use node_resolver::NodeResolutionKind;
@ -523,6 +524,8 @@ pub fn op_require_try_self<
TSys,
>>();
let referrer = UrlOrPathRef::from_path(&pkg.path);
// invalidate the resolution cache in case things have changed
NodeResolutionThreadLocalCache::clear();
let r = node_resolver.package_exports_resolve(
&pkg.path,
&expansion,
@ -626,6 +629,7 @@ pub fn op_require_resolve_exports<
} else {
Some(PathBuf::from(parent_path))
};
NodeResolutionThreadLocalCache::clear();
let r = node_resolver.package_exports_resolve(
&pkg.path,
&format!(".{expansion}"),
@ -708,6 +712,7 @@ pub fn op_require_package_imports_resolve<
TNpmPackageFolderResolver,
TSys,
>>();
NodeResolutionThreadLocalCache::clear();
let url = node_resolver.package_imports_resolve(
&request,
Some(&UrlOrPathRef::from_path(&referrer_path)),

View file

@ -23,6 +23,7 @@ use deno_npm::NpmSystemInfo;
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
use deno_path_util::normalize_path;
use futures::future::FutureExt;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::ConditionsFromResolutionMode;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use node_resolver::NodeResolver;
@ -561,6 +562,7 @@ pub struct ResolverFactoryOptions {
pub conditions_from_resolution_mode: ConditionsFromResolutionMode,
pub no_sloppy_imports_cache: bool,
pub npm_system_info: NpmSystemInfo,
pub node_resolution_cache: Option<node_resolver::NodeResolutionCacheRc>,
pub package_json_cache: Option<node_resolver::PackageJsonCacheRc>,
pub package_json_dep_resolution: Option<PackageJsonDepResolution>,
pub specified_import_map: Option<Box<dyn SpecifiedImportMapProvider>>,
@ -569,6 +571,7 @@ pub struct ResolverFactoryOptions {
pub struct ResolverFactory<TSys: WorkspaceFactorySys> {
options: ResolverFactoryOptions,
sys: NodeResolutionSys<TSys>,
deno_resolver: async_once_cell::OnceCell<DefaultDenoResolverRc<TSys>>,
in_npm_package_checker: Deferred<DenoInNpmPackageChecker>,
node_resolver: Deferred<
@ -602,6 +605,10 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
options: ResolverFactoryOptions,
) -> Self {
Self {
sys: NodeResolutionSys::new(
workspace_factory.sys.clone(),
options.node_resolution_cache.clone(),
),
deno_resolver: Default::default(),
in_npm_package_checker: Default::default(),
node_resolver: Default::default(),
@ -688,7 +695,7 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
DenoIsBuiltInNodeModuleChecker,
self.npm_resolver()?.clone(),
self.pkg_json_resolver().clone(),
self.workspace_factory.sys.clone(),
self.sys.clone(),
self.options.conditions_from_resolution_mode.clone(),
)))
})
@ -723,7 +730,7 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
self.npm_resolver.get_or_try_init(|| {
Ok(NpmResolver::<TSys>::new::<TSys>(if self.use_byonm()? {
NpmResolverCreateOptions::Byonm(ByonmNpmResolverCreateOptions {
sys: self.workspace_factory.sys.clone(),
sys: self.sys.clone(),
pkg_json_resolver: self.pkg_json_resolver().clone(),
root_node_modules_dir: Some(
match self.workspace_factory.node_modules_dir_path()? {

View file

@ -11,6 +11,7 @@ use deno_path_util::url_to_file_path;
use deno_semver::package::PackageReq;
use deno_semver::StackString;
use deno_semver::Version;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::errors::PackageFolderResolveError;
use node_resolver::errors::PackageFolderResolveIoError;
use node_resolver::errors::PackageJsonLoadError;
@ -48,7 +49,7 @@ pub enum ByonmResolvePkgFolderFromDenoReqError {
pub struct ByonmNpmResolverCreateOptions<TSys: FsRead> {
// todo(dsherret): investigate removing this
pub root_node_modules_dir: Option<PathBuf>,
pub sys: TSys,
pub sys: NodeResolutionSys<TSys>,
pub pkg_json_resolver: PackageJsonResolverRc<TSys>,
}
@ -60,7 +61,7 @@ pub type ByonmNpmResolverRc<TSys> =
pub struct ByonmNpmResolver<
TSys: FsCanonicalize + FsRead + FsMetadata + FsReadDir,
> {
sys: TSys,
sys: NodeResolutionSys<TSys>,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
root_node_modules_dir: Option<PathBuf>,
}
@ -136,14 +137,14 @@ impl<TSys: FsCanonicalize + FsRead + FsMetadata + FsReadDir>
referrer: &Url,
) -> Result<PathBuf, ByonmResolvePkgFolderFromDenoReqError> {
fn node_resolve_dir<TSys: FsCanonicalize + FsMetadata>(
sys: &TSys,
sys: &NodeResolutionSys<TSys>,
alias: &str,
start_dir: &Path,
) -> std::io::Result<Option<PathBuf>> {
for ancestor in start_dir.ancestors() {
let node_modules_folder = ancestor.join("node_modules");
let sub_dir = join_package_name(Cow::Owned(node_modules_folder), alias);
if sys.fs_is_dir_no_err(&sub_dir) {
if sys.is_dir(&sub_dir) {
return Ok(Some(
deno_path_util::fs::canonicalize_path_maybe_not_exists(
sys, &sub_dir,
@ -385,7 +386,7 @@ impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
referrer: &UrlOrPathRef,
) -> Result<PathBuf, PackageFolderResolveError> {
fn inner<TSys: FsMetadata>(
sys: &TSys,
sys: &NodeResolutionSys<TSys>,
name: &str,
referrer: &UrlOrPathRef,
) -> Result<PathBuf, PackageFolderResolveError> {
@ -402,7 +403,7 @@ impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
};
let sub_dir = join_package_name(node_modules_folder, name);
if sys.fs_is_dir_no_err(&sub_dir) {
if sys.is_dir(&sub_dir) {
return Ok(sub_dir);
}
}

197
resolvers/node/cache.rs Normal file
View file

@ -0,0 +1,197 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::cell::RefCell;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use sys_traits::BaseFsCanonicalize;
use sys_traits::BaseFsRead;
use sys_traits::BaseFsReadDir;
use sys_traits::FileType;
use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata;
use sys_traits::FsMetadataValue;
use sys_traits::FsRead;
use sys_traits::FsReadDir;
pub trait NodeResolutionCache:
std::fmt::Debug + crate::sync::MaybeSend + crate::sync::MaybeSync
{
fn get_canonicalized(
&self,
path: &Path,
) -> Option<Result<PathBuf, std::io::Error>>;
fn set_canonicalized(&self, from: PathBuf, to: &std::io::Result<PathBuf>);
fn get_file_type(&self, path: &Path) -> Option<Option<FileType>>;
fn set_file_type(&self, path: PathBuf, value: Option<FileType>);
}
thread_local! {
static CANONICALIZED_CACHE: RefCell<HashMap<PathBuf, Option<PathBuf>>> = RefCell::new(HashMap::new());
static FILE_TYPE_CACHE: RefCell<HashMap<PathBuf, Option<FileType>>> = RefCell::new(HashMap::new());
}
// We use thread local caches here because it's just more convenient
// and easily allows workers to have separate caches.
#[derive(Debug)]
pub struct NodeResolutionThreadLocalCache;
impl NodeResolutionThreadLocalCache {
pub fn clear() {
CANONICALIZED_CACHE.with_borrow_mut(|cache| cache.clear());
FILE_TYPE_CACHE.with_borrow_mut(|cache| cache.clear());
}
}
impl NodeResolutionCache for NodeResolutionThreadLocalCache {
fn get_canonicalized(
&self,
path: &Path,
) -> Option<Result<PathBuf, std::io::Error>> {
CANONICALIZED_CACHE.with_borrow(|cache| {
let item = cache.get(path)?;
Some(match item {
Some(value) => Ok(value.clone()),
None => Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Not found.",
)),
})
})
}
fn set_canonicalized(&self, from: PathBuf, to: &std::io::Result<PathBuf>) {
CANONICALIZED_CACHE.with_borrow_mut(|cache| match to {
Ok(to) => {
cache.insert(from, Some(to.clone()));
}
Err(err) => {
if err.kind() == std::io::ErrorKind::NotFound {
cache.insert(from, None);
}
}
});
}
fn get_file_type(&self, path: &Path) -> Option<Option<FileType>> {
FILE_TYPE_CACHE.with_borrow(|cache| cache.get(path).cloned())
}
fn set_file_type(&self, path: PathBuf, value: Option<FileType>) {
FILE_TYPE_CACHE.with_borrow_mut(|cache| {
cache.insert(path, value);
})
}
}
#[allow(clippy::disallowed_types)]
pub type NodeResolutionCacheRc = crate::sync::MaybeArc<dyn NodeResolutionCache>;
#[derive(Debug, Default)]
pub struct NodeResolutionSys<TSys> {
sys: TSys,
cache: Option<NodeResolutionCacheRc>,
}
impl<TSys: Clone> Clone for NodeResolutionSys<TSys> {
fn clone(&self) -> Self {
Self {
sys: self.sys.clone(),
cache: self.cache.clone(),
}
}
}
impl<TSys: FsMetadata> NodeResolutionSys<TSys> {
pub fn new(sys: TSys, store: Option<NodeResolutionCacheRc>) -> Self {
Self { sys, cache: store }
}
pub fn is_file(&self, path: &Path) -> bool {
match self.get_file_type(path) {
Ok(file_type) => file_type.is_file(),
Err(_) => false,
}
}
pub fn is_dir(&self, path: &Path) -> bool {
match self.get_file_type(path) {
Ok(file_type) => file_type.is_dir(),
Err(_) => false,
}
}
pub fn exists_(&self, path: &Path) -> bool {
self.get_file_type(path).is_ok()
}
pub fn get_file_type(&self, path: &Path) -> std::io::Result<FileType> {
{
if let Some(maybe_value) =
self.cache.as_ref().and_then(|c| c.get_file_type(path))
{
return match maybe_value {
Some(value) => Ok(value),
None => Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Not found.",
)),
};
}
}
match self.sys.fs_metadata(path) {
Ok(metadata) => {
if let Some(cache) = &self.cache {
cache.set_file_type(path.to_path_buf(), Some(metadata.file_type()));
}
Ok(metadata.file_type())
}
Err(err) => {
if let Some(cache) = &self.cache {
cache.set_file_type(path.to_path_buf(), None);
}
Err(err)
}
}
}
}
impl<TSys: FsCanonicalize> BaseFsCanonicalize for NodeResolutionSys<TSys> {
fn base_fs_canonicalize(&self, from: &Path) -> std::io::Result<PathBuf> {
if let Some(cache) = &self.cache {
if let Some(result) = cache.get_canonicalized(from) {
return result;
}
}
let result = self.sys.base_fs_canonicalize(from);
if let Some(cache) = &self.cache {
cache.set_canonicalized(from.to_path_buf(), &result);
}
result
}
}
impl<TSys: FsReadDir> BaseFsReadDir for NodeResolutionSys<TSys> {
type ReadDirEntry = TSys::ReadDirEntry;
#[inline(always)]
fn base_fs_read_dir(
&self,
path: &Path,
) -> std::io::Result<
Box<dyn Iterator<Item = std::io::Result<Self::ReadDirEntry>> + '_>,
> {
self.sys.base_fs_read_dir(path)
}
}
impl<TSys: FsRead> BaseFsRead for NodeResolutionSys<TSys> {
#[inline(always)]
fn base_fs_read(
&self,
path: &Path,
) -> std::io::Result<std::borrow::Cow<'static, [u8]>> {
self.sys.base_fs_read(path)
}
}

View file

@ -5,6 +5,7 @@
pub mod analyze;
mod builtin_modules;
pub mod cache;
pub mod errors;
mod npm;
mod package_json;
@ -16,6 +17,8 @@ mod sync;
pub use builtin_modules::DenoIsBuiltInNodeModuleChecker;
pub use builtin_modules::IsBuiltInNodeModuleChecker;
pub use builtin_modules::DENO_SUPPORTED_BUILTIN_NODE_MODULES;
pub use cache::NodeResolutionCache;
pub use cache::NodeResolutionCacheRc;
pub use deno_package_json::PackageJson;
pub use npm::InNpmPackageChecker;
pub use npm::NpmPackageFolderResolver;

View file

@ -15,10 +15,10 @@ use serde_json::Value;
use sys_traits::FileType;
use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata;
use sys_traits::FsMetadataValue;
use sys_traits::FsRead;
use url::Url;
use crate::cache::NodeResolutionSys;
use crate::errors;
use crate::errors::DataUrlReferrerError;
use crate::errors::FinalizeResolutionError;
@ -203,7 +203,7 @@ pub struct NodeResolver<
is_built_in_node_module_checker: TIsBuiltInNodeModuleChecker,
npm_pkg_folder_resolver: TNpmPackageFolderResolver,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
sys: TSys,
sys: NodeResolutionSys<TSys>,
conditions_from_resolution_mode: ConditionsFromResolutionMode,
}
@ -225,7 +225,7 @@ impl<
is_built_in_node_module_checker: TIsBuiltInNodeModuleChecker,
npm_pkg_folder_resolver: TNpmPackageFolderResolver,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
sys: TSys,
sys: NodeResolutionSys<TSys>,
conditions_from_resolution_mode: ConditionsFromResolutionMode,
) -> Self {
Self {
@ -434,12 +434,12 @@ impl<
path
};
let maybe_file_type = self.sys.fs_metadata(&path).map(|m| m.file_type());
let maybe_file_type = self.sys.get_file_type(&path);
match maybe_file_type {
Ok(FileType::Dir) => {
let suggested_file_name = ["index.mjs", "index.js", "index.cjs"]
.into_iter()
.find(|e| self.sys.fs_is_file_no_err(path.join(e)));
.find(|e| self.sys.is_file(&path.join(e)));
Err(
UnsupportedDirImportError {
dir_url: UrlOrPath::Path(path),
@ -492,7 +492,7 @@ impl<
if should_probe(path, resolved_method) {
["js", "mjs", "cjs"]
.into_iter()
.find(|ext| self.sys.fs_is_file_no_err(with_known_extension(path, ext)))
.find(|ext| self.sys.is_file(&with_known_extension(path, ext)))
} else {
None
}
@ -638,7 +638,7 @@ impl<
conditions: &[&str],
) -> Result<MaybeTypesResolvedUrl, TypesNotFoundError> {
fn probe_extensions<TSys: FsMetadata>(
sys: &TSys,
sys: &NodeResolutionSys<TSys>,
path: &Path,
media_type: MediaType,
resolution_mode: ResolutionMode,
@ -647,20 +647,20 @@ impl<
let mut searched_for_d_cts = false;
if media_type == MediaType::Mjs {
let d_mts_path = with_known_extension(path, "d.mts");
if sys.fs_is_file_no_err(&d_mts_path) {
if sys.exists_(&d_mts_path) {
return Some(d_mts_path);
}
searched_for_d_mts = true;
} else if media_type == MediaType::Cjs {
let d_cts_path = with_known_extension(path, "d.cts");
if sys.fs_is_file_no_err(&d_cts_path) {
if sys.exists_(&d_cts_path) {
return Some(d_cts_path);
}
searched_for_d_cts = true;
}
let dts_path = with_known_extension(path, "d.ts");
if sys.fs_is_file_no_err(&dts_path) {
if sys.exists_(&dts_path) {
return Some(dts_path);
}
@ -674,12 +674,12 @@ impl<
_ => None, // already searched above
};
if let Some(specific_dts_path) = specific_dts_path {
if sys.fs_is_file_no_err(&specific_dts_path) {
if sys.exists_(&specific_dts_path) {
return Some(specific_dts_path);
}
}
let ts_path = with_known_extension(path, "ts");
if sys.fs_is_file_no_err(&ts_path) {
if sys.is_file(&ts_path) {
return Some(ts_path);
}
None
@ -697,7 +697,7 @@ impl<
known_exists: true,
})));
}
if self.sys.fs_is_dir_no_err(&local_path.path) {
if self.sys.is_dir(&local_path.path) {
let resolution_result = self.resolve_package_dir_subpath(
&local_path.path,
/* sub path */ ".",
@ -1677,7 +1677,7 @@ impl<
if let Some(main) = maybe_main {
let guess = package_json.path.parent().unwrap().join(main).clean();
if self.sys.fs_is_file_no_err(&guess) {
if self.sys.is_file(&guess) {
return Ok(self.maybe_resolve_types(
LocalUrlOrPath::Path(LocalPath {
path: guess,
@ -1715,7 +1715,7 @@ impl<
.unwrap()
.join(format!("{main}{ending}"))
.clean();
if self.sys.fs_is_file_no_err(&guess) {
if self.sys.is_file(&guess) {
// TODO(bartlomieju): emitLegacyIndexDeprecation()
return Ok(MaybeTypesResolvedUrl(LocalUrlOrPath::Path(LocalPath {
path: guess,
@ -1753,7 +1753,7 @@ impl<
};
for index_file_name in index_file_names {
let guess = directory.join(index_file_name).clean();
if self.sys.fs_is_file_no_err(&guess) {
if self.sys.is_file(&guess) {
// TODO(bartlomieju): emitLegacyIndexDeprecation()
return Ok(MaybeTypesResolvedUrl(LocalUrlOrPath::Path(LocalPath {
path: guess,