mirror of https://github.com/webpack/webpack.git
Merge pull request #12631 from webpack/feature/resolve-hint
add some better hints when resolving fails
This commit is contained in:
commit
4ab27ff723
|
@ -750,35 +750,148 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
resolveContext,
|
||||
(err, resolvedResource, resolvedResourceResolveData) => {
|
||||
if (err) {
|
||||
if (resolver.options.fullySpecified) {
|
||||
resolver
|
||||
.withOptions({
|
||||
fullySpecified: false
|
||||
})
|
||||
.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
unresolvedResource,
|
||||
resolveContext,
|
||||
(err2, resolvedResource) => {
|
||||
if (!err2 && resolvedResource) {
|
||||
const resource = parseResource(
|
||||
resolvedResource
|
||||
).path.replace(/^.*[\\/]/, "");
|
||||
err.message += `
|
||||
Did you mean '${resource}'?
|
||||
return this._resolveResourceErrorHints(
|
||||
err,
|
||||
contextInfo,
|
||||
context,
|
||||
unresolvedResource,
|
||||
resolver,
|
||||
resolveContext,
|
||||
(err2, hints) => {
|
||||
if (err2) {
|
||||
err.message += `
|
||||
An fatal error happened during resolving additional hints for this error: ${err2.message}`;
|
||||
err.stack += `
|
||||
|
||||
An fatal error happened during resolving additional hints for this error:
|
||||
${err2.stack}`;
|
||||
return callback(err);
|
||||
}
|
||||
if (hints && hints.length > 0) {
|
||||
err.message += `
|
||||
${hints.join("\n\n")}`;
|
||||
}
|
||||
callback(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
callback(err, resolvedResource, resolvedResourceResolveData);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_resolveResourceErrorHints(
|
||||
error,
|
||||
contextInfo,
|
||||
context,
|
||||
unresolvedResource,
|
||||
resolver,
|
||||
resolveContext,
|
||||
callback
|
||||
) {
|
||||
asyncLib.parallel(
|
||||
[
|
||||
callback => {
|
||||
if (!resolver.options.fullySpecified) return callback();
|
||||
resolver
|
||||
.withOptions({
|
||||
fullySpecified: false
|
||||
})
|
||||
.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
unresolvedResource,
|
||||
resolveContext,
|
||||
(err, resolvedResource) => {
|
||||
if (!err && resolvedResource) {
|
||||
const resource = parseResource(resolvedResource).path.replace(
|
||||
/^.*[\\/]/,
|
||||
""
|
||||
);
|
||||
return callback(
|
||||
null,
|
||||
`Did you mean '${resource}'?
|
||||
BREAKING CHANGE: The request '${unresolvedResource}' failed to resolve only because it was resolved as fully specified
|
||||
(probably because the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"').
|
||||
The extension in the request is mandatory for it to be fully specified.
|
||||
Add the extension to the request.`;
|
||||
}
|
||||
callback(err);
|
||||
Add the extension to the request.`
|
||||
);
|
||||
}
|
||||
);
|
||||
return;
|
||||
callback();
|
||||
}
|
||||
);
|
||||
},
|
||||
callback => {
|
||||
if (!resolver.options.enforceExtension) return callback();
|
||||
resolver
|
||||
.withOptions({
|
||||
enforceExtension: false,
|
||||
extensions: []
|
||||
})
|
||||
.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
unresolvedResource,
|
||||
resolveContext,
|
||||
(err, resolvedResource) => {
|
||||
if (!err && resolvedResource) {
|
||||
let hint = "";
|
||||
const match = /(\.[^.]+)(\?|$)/.exec(unresolvedResource);
|
||||
if (match) {
|
||||
const fixedRequest = unresolvedResource.replace(
|
||||
/(\.[^.]+)(\?|$)/,
|
||||
"$2"
|
||||
);
|
||||
if (resolver.options.extensions.has(match[1])) {
|
||||
hint = `Did you mean '${fixedRequest}'?`;
|
||||
} else {
|
||||
hint = `Did you mean '${fixedRequest}'? Also note that '${match[1]}' is not in 'resolve.extensions' yet and need to be added for this to work?`;
|
||||
}
|
||||
} else {
|
||||
hint = `Did you mean to omit the extension or to remove 'resolve.enforceExtension'?`;
|
||||
}
|
||||
return callback(
|
||||
null,
|
||||
`The request '${unresolvedResource}' failed to resolve only because 'resolve.enforceExtension' was specified.
|
||||
${hint}
|
||||
Including the extension in the request is no longer possible. Did you mean to enforce including the extension in requests with 'resolve.extensions: []' instead?`
|
||||
);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
);
|
||||
},
|
||||
callback => {
|
||||
if (
|
||||
/^\.\.?\//.test(unresolvedResource) ||
|
||||
resolver.options.preferRelative
|
||||
) {
|
||||
return callback();
|
||||
}
|
||||
resolver.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
`./${unresolvedResource}`,
|
||||
resolveContext,
|
||||
(err, resolvedResource) => {
|
||||
if (err || !resolvedResource) return callback();
|
||||
const moduleDirectories = resolver.options.modules
|
||||
.map(m => (Array.isArray(m) ? m.join(", ") : m))
|
||||
.join(", ");
|
||||
callback(
|
||||
null,
|
||||
`Did you mean './${unresolvedResource}'?
|
||||
Requests that should resolve in the current directory need to start with './'.
|
||||
Requests that start with a name are treated as module requests and resolve within module directories (${moduleDirectories}).
|
||||
If changing the source code is not an option there is also a resolve options called 'preferRelative' which tries to resolve these kind of requests in the current directory too.`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
callback(err, resolvedResource, resolvedResourceResolveData);
|
||||
],
|
||||
(err, hints) => {
|
||||
if (err) return callback(err);
|
||||
callback(null, hints.filter(Boolean));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export {};
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = [
|
||||
[/Can't resolve 'dependency\.js'/, /Did you mean '\.\/dependency\.js'\?/]
|
||||
];
|
|
@ -0,0 +1,5 @@
|
|||
it("should not resolve module requests relative", async () => {
|
||||
await expect(import("./module.mjs")).rejects.toMatchObject({
|
||||
code: "MODULE_NOT_FOUND"
|
||||
});
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
import "dependency.js";
|
Loading…
Reference in New Issue