Skip to content

Commit

Permalink
feat: add hint for missing resolve.extensions when resolving module (#…
Browse files Browse the repository at this point in the history
…5680)

* feat: add resolve extension fail hint

* chore: update resolve message

* refactor: give a hint when the relative paths aren't resolved

* chore: update test case

* fix: comment

* fix: clippy warning

* fix: clippy
  • Loading branch information
luhc228 authored Feb 26, 2024
1 parent f8bf50f commit d1fe2d1
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 1 deletion.
98 changes: 97 additions & 1 deletion crates/rspack_core/src/resolver/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod factory;
mod resolver_impl;

use std::borrow::Borrow;
use std::fs;
use std::{fmt, path::PathBuf};

use once_cell::sync::Lazy;
Expand Down Expand Up @@ -169,6 +170,101 @@ which tries to resolve these kind of requests in the current directory too.",
}
}

// try to resolve relative path with extension
if RELATIVE_PATH_REGEX.is_match(args.specifier) {
let connected_path = base_dir.join(args.specifier);
let normalized_path = connected_path.absolutize();

let mut is_resolving_dir = false; // whether the request is to resolve a directory or not

let file_name = normalized_path.file_name();
let parent_path = match fs::metadata(&normalized_path) {
Ok(metadata) => {
// if the path is not directory, we need to resolve the parent directory
if !metadata.is_dir() {
normalized_path.parent()
} else {
is_resolving_dir = true;
Some(normalized_path.borrow())
}
}
Err(_) => normalized_path.parent(),
};

if file_name.is_some() && parent_path.is_some() {
let file_name = file_name.expect("fail to get the filename of the current resolved module");
let parent_path =
parent_path.expect("fail to get the parent path of the current resolved module");

// read the files in the parent directory
let files = fs::read_dir(parent_path);
match files {
Ok(files) => {
let mut requested_names = vec![file_name
.to_str()
.map(|f| f.to_string())
.unwrap_or_default()];
if is_resolving_dir {
// The request maybe is like `./` or `./dir` to resolve the main file (e.g.: index) in directory
// So we need to check them.
let main_files = dep
.resolve_options
.as_deref()
.or(Some(&plugin_driver.options.resolve))
.and_then(|o| o.main_files.as_ref().cloned())
.unwrap_or_default();

requested_names.extend(main_files);
}

let suggestions = files
.into_iter()
.filter_map(|file| {
file.ok().and_then(|file| {
file.path().file_stem().and_then(|file_stem| {
if requested_names.contains(&file_stem.to_string_lossy().to_string()) {
let mut suggestion = file.path().relative(args.context.as_path());

if !suggestion.to_string_lossy().starts_with('.') {
suggestion = PathBuf::from(format!("./{}", suggestion.to_string_lossy()));
}
Some(suggestion)
} else {
None
}
})
})
})
.collect::<Vec<_>>();

if suggestions.is_empty() {
return None;
}

let mut hint: Vec<String> = vec![];
for suggestion in suggestions {
let suggestion_ext = suggestion
.extension()
.map(|e| e.to_string_lossy())
.unwrap_or_default();
let suggestion_path = suggestion.to_string_lossy();
let specifier = args.specifier;

hint.push(format!(
"Found the module '{suggestion_path}' exists, but its extension is not listed in the `resolve.extensions`. Here are some possible solutions:
1. add the extension `\".{suggestion_ext}\"` to `resolve.extensions` in your rspack configuration
2. use '{suggestion_path}' instead of '{specifier}'
"));
}

return Some(hint.join("\n"));
}
Err(_) => return None,
}
}
}

None
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
ERROR in Γ— Resolve error: Can't resolve './' in '<PROJECT_ROOT>/tests/diagnostics/builtins/recoverable_syntax_error'
help: Found the module './index.tsx' exists, but its extension is not listed in the `resolve.extensions`. Here are some possible solutions:

1. add the extension `".tsx"` to `resolve.extensions` in your rspack configuration
2. use './index.tsx' instead of './'
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import a from '../a';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import './err';
import './test';
import a from './a';
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
ERROR in ./err/index.js
Γ— Resolve error: Can't resolve '../a' in '<PROJECT_ROOT>/tests/diagnostics/factorize/resolve-extensions-error/err'
╭────
1 β”‚ import a from '../a';
Β· ──────
╰────
help: Found the module '../a.txt' exists, but its extension is not listed in the `resolve.extensions`. Here are some possible solutions:

1. add the extension `".txt"` to `resolve.extensions` in your rspack configuration
2. use '../a.txt' instead of '../a'

ERROR in ./index.js
Γ— Resolve error: Can't resolve './test' in '<PROJECT_ROOT>/tests/diagnostics/factorize/resolve-extensions-error'
╭─[1:1]
1 β”‚ import './err';
2 β”‚ import './test';
Β· ────────
3 β”‚ import a from './a';
╰────
help: Found the module './test/index.txt' exists, but its extension is not listed in the `resolve.extensions`. Here are some possible solutions:

1. add the extension `".txt"` to `resolve.extensions` in your rspack configuration
2. use './test/index.txt' instead of './test'

ERROR in ./index.js
Γ— Resolve error: Can't resolve './a' in '<PROJECT_ROOT>/tests/diagnostics/factorize/resolve-extensions-error'
╭─[1:1]
1 β”‚ import './err';
2 β”‚ import './test';
3 β”‚ import a from './a';
Β· ─────
╰────
help: Found the module './a.txt' exists, but its extension is not listed in the `resolve.extensions`. Here are some possible solutions:

1. add the extension `".txt"` to `resolve.extensions` in your rspack configuration
2. use './a.txt' instead of './a'
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module.exports = {
}

1 comment on commit d1fe2d1

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“ Benchmark detail: Open

Name Base (2024-02-26 531a19a) Current Change
10000_development-mode + exec 1.7 s Β± 26 ms 1.7 s Β± 13 ms -0.06 %
10000_development-mode_hmr + exec 920 ms Β± 13 ms 925 ms Β± 11 ms +0.48 %
10000_production-mode + exec 2.65 s Β± 53 ms 2.68 s Β± 59 ms +1.01 %
arco-pro_development-mode + exec 2.45 s Β± 34 ms 2.46 s Β± 28 ms +0.43 %
arco-pro_development-mode_hmr + exec 877 ms Β± 20 ms 863 ms Β± 15 ms -1.51 %
arco-pro_production-mode + exec 4.07 s Β± 42 ms 4.15 s Β± 38 ms +2.12 %
threejs_development-mode_10x + exec 1.9 s Β± 36 ms 1.9 s Β± 16 ms +0.05 %
threejs_development-mode_10x_hmr + exec 1.13 s Β± 10 ms 1.13 s Β± 12 ms +0.26 %
threejs_production-mode_10x + exec 5.83 s Β± 31 ms 5.65 s Β± 31 ms -3.13 %

Please sign in to comment.