perf(resolver): reduce memory allocation when resolving node_modules (#608)

This commit is contained in:
Boshen 2023-07-25 20:06:44 +08:00 committed by GitHub
parent f094d5881e
commit b78b1ebdca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -285,37 +285,42 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
fn load_node_modules(&self, cache_value: &CacheValue, request: &str) -> ResolveState {
// 1. let DIRS = NODE_MODULES_PATHS(START)
let dirs = self.node_module_paths(cache_value.path());
// Use a buffer to reduce total memory allocation.
let mut node_module_path = cache_value.path().to_path_buf();
// 2. for each DIR in DIRS:
for node_module_path in dirs {
// a. LOAD_PACKAGE_EXPORTS(X, DIR)
if let Some(path) = self.load_package_exports(&node_module_path, request)? {
return Ok(Some(path));
loop {
for module_name in &self.options.modules {
node_module_path.push(module_name);
// a. LOAD_PACKAGE_EXPORTS(X, DIR)
if let Some(path) = self.load_package_exports(&node_module_path, request)? {
return Ok(Some(path));
}
// Using `join` because `request` can be `/` separated.
let node_module_file = node_module_path.join(request);
let cache_value = self.cache.value(&node_module_file);
// b. LOAD_AS_FILE(DIR/X)
if !request.ends_with('/') {
if let Some(path) = self.load_as_file(&cache_value)? {
return Ok(Some(path));
}
}
// c. LOAD_AS_DIRECTORY(DIR/X)
if cache_value.is_dir(&self.cache.fs) {
if let Some(path) = self.load_as_directory(&cache_value)? {
return Ok(Some(path));
}
}
node_module_path.pop();
}
let node_module_file = node_module_path.join(request);
let cache_value = self.cache.value(&node_module_file);
// b. LOAD_AS_FILE(DIR/X)
if !request.ends_with('/') {
if let Some(path) = self.load_as_file(&cache_value)? {
return Ok(Some(path));
}
}
// c. LOAD_AS_DIRECTORY(DIR/X)
if cache_value.is_dir(&self.cache.fs) {
if let Some(path) = self.load_as_directory(&cache_value)? {
return Ok(Some(path));
}
if !node_module_path.pop() {
break;
}
}
Ok(None)
}
fn node_module_paths<'a>(&'a self, path: &'a Path) -> impl Iterator<Item = PathBuf> + 'a {
path.ancestors()
.flat_map(|path| self.options.modules.iter().map(|module| path.join(module)))
}
#[allow(clippy::unnecessary_wraps, clippy::unused_self)]
fn load_package_exports(&self, _path: &Path, _request: &str) -> ResolveState {
// 1. Try to interpret X as a combination of NAME and SUBPATH where the name