How to write plugin that adds resolve.extensions when it is not defined in config? #19170
-
Hi, im trying to write simple plugin that adds extensions in configuration. I write this logic in my plugin: compiler.hooks.afterEnvironment.tap('MyPlugin', () => {
if (!compiler.options.resolve.extensions) {
compiler.options.resolve.extensions = ['...'];
}
const { extensions } = compiler.options.resolve;
for (const ext of ['.ts', '.tsx']) {
if (!extensions.includes(ext)) {
extensions.push(ext);
}
}
}); Its working only when extensions provided in configuration object. Even if empty array is provided. It is not working if I asked same question here web-infra-dev/rspack#8994 |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
You solution is right
Can you clarify? Yes, this is expected, it is too later modify global options, because default options already applied (short answer). Long answer - resolver is more complex than you could think. We have concept of /** @type {function(): ResolveOptions} */
const jsExtensions = [".js", ".json", ".wasm"];
const esmDeps = () => ({
aliasFields: browserField ? ["browser"] : [],
mainFields: browserField ? ["browser", "module", "..."] : ["module", "..."],
conditionNames: ["import", "module", "..."],
extensions: [...jsExtensions]
}); When we try to union global options with dependencies options (and there is a problem, we use them from above, not from compiler options, we still store them to recreate resolver in some cases, but in your case they are not used). But For example, this will work: {
apply(compiler) {
compiler.hooks.afterEnvironment.tap("MyPlugin", () => {
const { extensions } = compiler.options.resolve.byDependency["esm"];
for (const ext of [".test"]) {
if (!extensions.includes(ext)) {
extensions.push(ext);
}
}
});
}
} But I don't think you want to use this logic only for ESM, I think you want to use for any You can use this code to make {
plugins: [
{
apply(compiler) {
if (!compiler.options.resolve.extensions) {
compiler.options.resolve.extensions = ['...'];
}
const { extensions } = compiler.options.resolve;
for (const ext of ['.test']) {
if (!extensions.includes(ext)) {
extensions.push(ext);
}
}
}
}
],
} Alternative solution change options when resolver is creating: {
apply(compiler) {
compiler.resolverFactory.hooks.resolveOptions
.for("normal")
.tap({ name: "Name", stage: 100 }, resolveOptions => {
// dependencyType = "esm" | "commonjs" | "url" | "css" | "sass" | "wasm" and more
const { dependencyType } = resolveOptions;
resolveOptions.byDependency[dependencyType].extensions.push(
".test"
);
return resolveOptions;
});
}
} Resolving is really complex thing, because different module system use different logic |
Beta Was this translation helpful? Give feedback.
You solution is right
Can you clarify?
Yes, this is expected, it is too later modify global options, because default options already applied (short answer).
Long answer - resolver is more complex than you could think. We have concept of
byDependency
resolver, i.e. resolving for commonjs, esm, css are different (and use different options) so our code doing this stuff: