diff --git a/lib/Compilation.js b/lib/Compilation.js index 6e73dc3afa5..9ebce7834f3 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -1436,7 +1436,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si * @returns {void} */ _processModuleDependencies(module, callback) { - /** @type {Array<{factory: ModuleFactory, dependencies: Dependency[], originModule: Module|null}>} */ + /** @type {Array<{factory: ModuleFactory, dependencies: Dependency[], context: string|undefined, originModule: Module|null}>} */ const sortedDependencies = []; /** @type {DependenciesBlock} */ @@ -1668,6 +1668,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si sortedDependencies.push({ factory: factoryCacheKey2, dependencies: list, + context: dep.getContext(), originModule: module }); } diff --git a/lib/ContextModuleFactory.js b/lib/ContextModuleFactory.js index 9bd50d916b0..6acab513d2a 100644 --- a/lib/ContextModuleFactory.js +++ b/lib/ContextModuleFactory.js @@ -292,7 +292,6 @@ module.exports = class ContextModuleFactory extends ModuleFactory { } = options; if (!regExp || !resource) return callback(null, []); - let severalContexts = false; const addDirectoryChecked = (ctx, directory, visited, callback) => { fs.realpath(directory, (err, realPath) => { if (err) return callback(err); @@ -359,15 +358,13 @@ module.exports = class ContextModuleFactory extends ModuleFactory { alternatives = alternatives .filter(obj => regExp.test(obj.request)) .map(obj => { - const request = severalContexts - ? join(fs, obj.context, obj.request) - : obj.request; const dep = new ContextElementDependency( - request + resourceQuery + resourceFragment, + `${obj.request}${resourceQuery}${resourceFragment}`, obj.request, typePrefix, category, - referencedExports + referencedExports, + obj.context ); dep.optional = true; return dep; @@ -414,7 +411,6 @@ module.exports = class ContextModuleFactory extends ModuleFactory { if (typeof resource === "string") { visitResource(resource, callback); } else { - severalContexts = true; asyncLib.map(resource, visitResource, (err, result) => { if (err) return callback(err); diff --git a/lib/Dependency.js b/lib/Dependency.js index 7ffc363fef3..a9ec0cd08f8 100644 --- a/lib/Dependency.js +++ b/lib/Dependency.js @@ -182,6 +182,13 @@ class Dependency { this._loc = undefined; } + /** + * @returns {string | undefined} a request context + */ + getContext() { + return undefined; + } + /** * @returns {string | null} an identifier to merge equal requests */ diff --git a/lib/dependencies/ContextElementDependency.js b/lib/dependencies/ContextElementDependency.js index 0ea6bfdaf72..ec0390e85ce 100644 --- a/lib/dependencies/ContextElementDependency.js +++ b/lib/dependencies/ContextElementDependency.js @@ -14,11 +14,27 @@ const ModuleDependency = require("./ModuleDependency"); /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */ class ContextElementDependency extends ModuleDependency { - constructor(request, userRequest, typePrefix, category, referencedExports) { + /** + * @param {string} request request + * @param {string|undefined} userRequest user request + * @param {string} typePrefix type prefix + * @param {string} category category + * @param {string[][]=} referencedExports referenced exports + * @param {string=} context context + */ + constructor( + request, + userRequest, + typePrefix, + category, + referencedExports, + context + ) { super(request); this.referencedExports = referencedExports; this._typePrefix = typePrefix; this._category = category; + this._context = context || undefined; if (userRequest) { this.userRequest = userRequest; @@ -33,6 +49,20 @@ class ContextElementDependency extends ModuleDependency { return "context element"; } + /** + * @returns {string | undefined} a request context + */ + getContext() { + return this._context; + } + + /** + * @returns {string | null} an identifier to merge equal requests + */ + getResourceIdentifier() { + return `context${this._context || ""}|${super.getResourceIdentifier()}`; + } + get category() { return this._category; } @@ -56,6 +86,7 @@ class ContextElementDependency extends ModuleDependency { const { write } = context; write(this._typePrefix); write(this._category); + write(this._context); write(this.referencedExports); super.serialize(context); } @@ -64,6 +95,7 @@ class ContextElementDependency extends ModuleDependency { const { read } = context; this._typePrefix = read(); this._category = read(); + this._context = read(); this.referencedExports = read(); super.deserialize(context); } diff --git a/test/ContextModuleFactory.unittest.js b/test/ContextModuleFactory.unittest.js index 1f89e611d4f..e294bb21ceb 100644 --- a/test/ContextModuleFactory.unittest.js +++ b/test/ContextModuleFactory.unittest.js @@ -148,9 +148,10 @@ describe("ContextModuleFactory", () => { expect(res).not.toStrictEqual([]); expect(Array.isArray(res)).toBe(true); expect(res.map(r => r.request)).toEqual([ - "/a/B/a?query#hash", - "/b/A/b?query#hash" + "./B/a?query#hash", + "./A/b?query#hash" ]); + expect(res.map(r => r.getContext())).toEqual(["/a", "/b"]); expect(res.map(r => r.userRequest)).toEqual(["./B/a", "./A/b"]); done(); } diff --git a/test/configCases/resolve/issue-15580/index.js b/test/configCases/resolve/issue-15580/index.js new file mode 100644 index 00000000000..6b17761ce31 --- /dev/null +++ b/test/configCases/resolve/issue-15580/index.js @@ -0,0 +1,19 @@ +const locales = import.meta.webpackContext('./locales', { + recursive: false, + regExp: /(en|hu)\.json$/i, +}); +const vuetify = import.meta.webpackContext('vuetify/lib/locale', { + recursive: false, + regExp: /(en|hu)\.json$/i, +}); + +it('should resolve "./locales"', () => { + expect(locales("./en.json")).toEqual({}); + expect(() => locales("./hu.json")).toThrow(); +}); + +it('should resolve "vuetify"', () => { + expect(vuetify("./en.json")).toEqual({}); + expect(vuetify("./hu.json")).toEqual({}); + expect(() => vuetify("./ru.json")).toThrow(); +}); diff --git a/test/configCases/resolve/issue-15580/locales/en.json b/test/configCases/resolve/issue-15580/locales/en.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/test/configCases/resolve/issue-15580/locales/en.json @@ -0,0 +1 @@ +{} diff --git a/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/en.json b/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/en.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/en.json @@ -0,0 +1 @@ +{} diff --git a/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/hu.json b/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/hu.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/hu.json @@ -0,0 +1 @@ +{} diff --git a/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/ru.json b/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/ru.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/test/configCases/resolve/issue-15580/node_modules/vuetify/lib/locale/ru.json @@ -0,0 +1 @@ +{} diff --git a/test/configCases/resolve/issue-15580/node_modules/vuetify/package.json b/test/configCases/resolve/issue-15580/node_modules/vuetify/package.json new file mode 100644 index 00000000000..91189b88e1d --- /dev/null +++ b/test/configCases/resolve/issue-15580/node_modules/vuetify/package.json @@ -0,0 +1,4 @@ +{ + "name": "vuetify", + "version": "1.0.0" +} diff --git a/test/configCases/resolve/issue-15580/webpack.config.js b/test/configCases/resolve/issue-15580/webpack.config.js new file mode 100644 index 00000000000..c39ef077cad --- /dev/null +++ b/test/configCases/resolve/issue-15580/webpack.config.js @@ -0,0 +1,8 @@ +const path = require("path"); + +/** @type {import("../../../../").Configuration} */ +module.exports = { + resolve: { + modules: ["node_modules", path.resolve(__dirname, "./node_modules")] + } +}; diff --git a/types.d.ts b/types.d.ts index 6329c416fcc..b977fed15ec 100644 --- a/types.d.ts +++ b/types.d.ts @@ -2462,7 +2462,7 @@ declare interface ContainerReferencePluginOptions { shareScope?: string; } declare abstract class ContextElementDependency extends ModuleDependency { - referencedExports: any; + referencedExports?: string[][]; } declare class ContextExclusionPlugin { constructor(negativeMatcher: RegExp); @@ -2645,6 +2645,7 @@ declare class Dependency { endLine?: any, endColumn?: any ): void; + getContext(): undefined | string; getResourceIdentifier(): null | string; couldAffectReferencingModule(): boolean | typeof TRANSITIVE;