diff --git a/lib/ModuleLayerCache.js b/lib/ModuleLayerCache.js index 2708ef1824c..f8f1ec3fcf2 100644 --- a/lib/ModuleLayerCache.js +++ b/lib/ModuleLayerCache.js @@ -70,7 +70,9 @@ class ModuleLayerCache { * @param {string | Buffer} value The value to store in the cache. */ set(key, value) { - const weakMapKey = new WeakMapKey(key); + const weakMapKey = this.weakMapKeys.has(key) + ? this.weakMapKeys.get(key) + : new WeakMapKey(key); this.weakMapKeys.set(key, weakMapKey); this.cachedValues.set(weakMapKey, value); } diff --git a/lib/NormalModule.js b/lib/NormalModule.js index 374fd66df2a..066095b7eb0 100644 --- a/lib/NormalModule.js +++ b/lib/NormalModule.js @@ -232,8 +232,8 @@ makeSerializable( /** @type {WeakMap} */ const compilationHooksMap = new WeakMap(); -/** @type {ModuleLayerCache} */ -const moduleLayerCache = new ModuleLayerCache(); +/** @type {WeakMap} */ +const cachedModuleLayerCaches = new WeakMap(); class NormalModule extends Module { /** @@ -784,6 +784,31 @@ class NormalModule extends Module { * @returns {Source} the created source */ createSource(context, content, sourceMap, associatedObjectForCache) { + // If this module exists in a layer, try to reuse the value for the + // source string so it is not duplicated in multiple modules. + if (this.layer && this.userRequest) { + let moduleLayerCache = cachedModuleLayerCaches.get( + associatedObjectForCache + ); + if (moduleLayerCache) { + moduleLayerCache = new ModuleLayerCache(); + cachedModuleLayerCaches.set(associatedObjectForCache, moduleLayerCache); + } + if (moduleLayerCache.has(this.userRequest)) { + const cachedSource = moduleLayerCache.get(this.userRequest); + if ( + (Buffer.isBuffer(content) && + Buffer.isBuffer(cachedSource) && + content.equals(cachedSource)) || + content === cachedSource + ) { + content = cachedSource; + } + } else { + moduleLayerCache.set(this.userRequest, content); + } + } + if (Buffer.isBuffer(content)) { return new RawSource(content); } @@ -871,24 +896,6 @@ class NormalModule extends Module { return callback(error); } - // If this module exists in a layer, try to reuse the value for the - // source string so it is not duplicated in multiple modules. - if (this.layer && this.request) { - if (moduleLayerCache.has(this.request)) { - const cachedSource = moduleLayerCache.get(this.request); - if ( - (Buffer.isBuffer(source) && - Buffer.isBuffer(cachedSource) && - source.equals(cachedSource)) || - source === cachedSource - ) { - source = cachedSource; - } - } else { - moduleLayerCache.set(this.request, source); - } - } - this._source = this.createSource( /** @type {string} */ (options.context), this.binary ? asBuffer(source) : asString(source), diff --git a/lib/json/JsonModulesPlugin.js b/lib/json/JsonModulesPlugin.js index 5b998482870..0d60d1e88a3 100644 --- a/lib/json/JsonModulesPlugin.js +++ b/lib/json/JsonModulesPlugin.js @@ -44,7 +44,7 @@ class JsonModulesPlugin { .tap(PLUGIN_NAME, parserOptions => { validate(parserOptions); - return new JsonParser(parserOptions); + return new JsonParser(parserOptions, compilation); }); normalModuleFactory.hooks.createGenerator .for(JSON_MODULE_TYPE) diff --git a/lib/json/JsonParser.js b/lib/json/JsonParser.js index b3bc4277e73..fcd24fc7687 100644 --- a/lib/json/JsonParser.js +++ b/lib/json/JsonParser.js @@ -20,16 +20,18 @@ const JsonData = require("./JsonData"); const getParseJson = memoize(() => require("json-parse-even-better-errors")); -/** @type {ModuleLayerCache} */ -const moduleLayerCache = new ModuleLayerCache(); +/** @type {WeakMap} */ +const cachedModuleLayerCaches = new WeakMap(); class JsonParser extends Parser { /** * @param {JsonModulesPluginParserOptions} options parser options + * @param {Object} associatedObjectForCache An object to associate cached data with. */ - constructor(options) { + constructor(options, associatedObjectForCache) { super(); this.options = options || {}; + this.associatedObjectForCache = associatedObjectForCache; } /** @@ -61,14 +63,24 @@ class JsonParser extends Parser { // If the module is associated with a layer, try to reuse cached data instead // of duplicating the data multiple times. const module = state.module; - if (module && module.request && module.layer && Buffer.isBuffer(data)) { - if (moduleLayerCache.has(module.request)) { - const cachedData = moduleLayerCache.get(module.request); + if (module && module.userRequest && module.layer && Buffer.isBuffer(data)) { + let moduleLayerCache = cachedModuleLayerCaches.get( + this.associatedObjectForCache + ); + if (moduleLayerCache) { + moduleLayerCache = new ModuleLayerCache(); + cachedModuleLayerCaches.set( + this.associatedObjectForCache, + moduleLayerCache + ); + } + if (moduleLayerCache.has(module.userRequest)) { + const cachedData = moduleLayerCache.get(module.userRequest); if (Buffer.isBuffer(cachedData) && data.equals(cachedData)) { data = cachedData; } } else { - moduleLayerCache.set(module.request, data); + moduleLayerCache.set(module.userRequest, data); } }