code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const ModuleNotFoundError = require("../ModuleNotFoundError");
const RuntimeGlobals = require("../RuntimeGlobals");
const WebpackError = require("../WebpackError");
const { parseOptions } = require("../container/options");
const LazySet = require("../util/LazySet");
const createSchemaValidation = require("../util/create-schema-validation");
const { parseRange } = require("../util/semver");
const ConsumeSharedFallbackDependency = require("./ConsumeSharedFallbackDependency");
const ConsumeSharedModule = require("./ConsumeSharedModule");
const ConsumeSharedRuntimeModule = require("./ConsumeSharedRuntimeModule");
const ProvideForSharedDependency = require("./ProvideForSharedDependency");
const { resolveMatchedConfigs } = require("./resolveMatchedConfigs");
const {
	isRequiredVersion,
	getDescriptionFile,
	getRequiredVersionFromDescriptionFile
} = require("./utils");

/** @typedef {import("../../declarations/plugins/sharing/ConsumeSharedPlugin").ConsumeSharedPluginOptions} ConsumeSharedPluginOptions */
/** @typedef {import("../../declarations/plugins/sharing/ConsumeSharedPlugin").ConsumesConfig} ConsumesConfig */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../ResolverFactory").ResolveOptionsWithDependencyType} ResolveOptionsWithDependencyType */
/** @typedef {import("./ConsumeSharedModule").ConsumeOptions} ConsumeOptions */

const validate = createSchemaValidation(
	require("../../schemas/plugins/sharing/ConsumeSharedPlugin.check.js"),
	() => require("../../schemas/plugins/sharing/ConsumeSharedPlugin.json"),
	{
		name: "Consume Shared Plugin",
		baseDataPath: "options"
	}
);

/** @type {ResolveOptionsWithDependencyType} */
const RESOLVE_OPTIONS = { dependencyType: "esm" };
const PLUGIN_NAME = "ConsumeSharedPlugin";

class ConsumeSharedPlugin {
	/**
	 * @param {ConsumeSharedPluginOptions} options options
	 */
	constructor(options) {
		if (typeof options !== "string") {
			validate(options);
		}

		/** @type {[string, ConsumeOptions][]} */
		this._consumes = parseOptions(
			options.consumes,
			(item, key) => {
				if (Array.isArray(item)) throw new Error("Unexpected array in options");
				/** @type {ConsumeOptions} */
				let result =
					item === key || !isRequiredVersion(item)
						? // item is a request/key
							{
								import: key,
								shareScope: options.shareScope || "default",
								shareKey: key,
								requiredVersion: undefined,
								packageName: undefined,
								strictVersion: false,
								singleton: false,
								eager: false
							}
						: // key is a request/key
							// item is a version
							{
								import: key,
								shareScope: options.shareScope || "default",
								shareKey: key,
								requiredVersion: parseRange(item),
								strictVersion: true,
								packageName: undefined,
								singleton: false,
								eager: false
							};
				return result;
			},
			(item, key) => ({
				import: item.import === false ? undefined : item.import || key,
				shareScope: item.shareScope || options.shareScope || "default",
				shareKey: item.shareKey || key,
				requiredVersion:
					typeof item.requiredVersion === "string"
						? parseRange(item.requiredVersion)
						: item.requiredVersion,
				strictVersion:
					typeof item.strictVersion === "boolean"
						? item.strictVersion
						: item.import !== false && !item.singleton,
				packageName: item.packageName,
				singleton: !!item.singleton,
				eager: !!item.eager
			})
		);
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.thisCompilation.tap(
			PLUGIN_NAME,
			(compilation, { normalModuleFactory }) => {
				compilation.dependencyFactories.set(
					ConsumeSharedFallbackDependency,
					normalModuleFactory
				);

				/** @type {Map<string, ConsumeOptions>} */
				let unresolvedConsumes;
				/** @type {Map<string, ConsumeOptions>} */
				let resolvedConsumes;
				/** @type {Map<string, ConsumeOptions>} */
				let prefixedConsumes;
				const promise = resolveMatchedConfigs(compilation, this._consumes).then(
					({ resolved, unresolved, prefixed }) => {
						resolvedConsumes = resolved;
						unresolvedConsumes = unresolved;
						prefixedConsumes = prefixed;
					}
				);

				const resolver = compilation.resolverFactory.get(
					"normal",
					RESOLVE_OPTIONS
				);

				/**
				 * @param {string} context issuer directory
				 * @param {string} request request
				 * @param {ConsumeOptions} config options
				 * @returns {Promise<ConsumeSharedModule>} create module
				 */
				const createConsumeSharedModule = (context, request, config) => {
					/**
					 * @param {string} details details
					 */
					const requiredVersionWarning = details => {
						const error = new WebpackError(
							`No required version specified and unable to automatically determine one. ${details}`
						);
						error.file = `shared module ${request}`;
						compilation.warnings.push(error);
					};
					const directFallback =
						config.import &&
						/^(\.\.?(\/|$)|\/|[A-Za-z]:|\\\\)/.test(config.import);
					return Promise.all([
						new Promise(resolve => {
							if (!config.import) return resolve();
							const resolveContext = {
								/** @type {LazySet<string>} */
								fileDependencies: new LazySet(),
								/** @type {LazySet<string>} */
								contextDependencies: new LazySet(),
								/** @type {LazySet<string>} */
								missingDependencies: new LazySet()
							};
							resolver.resolve(
								{},
								directFallback ? compiler.context : context,
								config.import,
								resolveContext,
								(err, result) => {
									compilation.contextDependencies.addAll(
										resolveContext.contextDependencies
									);
									compilation.fileDependencies.addAll(
										resolveContext.fileDependencies
									);
									compilation.missingDependencies.addAll(
										resolveContext.missingDependencies
									);
									if (err) {
										compilation.errors.push(
											new ModuleNotFoundError(null, err, {
												name: `resolving fallback for shared module ${request}`
											})
										);
										return resolve();
									}
									resolve(result);
								}
							);
						}),
						new Promise(resolve => {
							if (config.requiredVersion !== undefined)
								return resolve(config.requiredVersion);
							let packageName = config.packageName;
							if (packageName === undefined) {
								if (/^(\/|[A-Za-z]:|\\\\)/.test(request)) {
									// For relative or absolute requests we don't automatically use a packageName.
									// If wished one can specify one with the packageName option.
									return resolve();
								}
								const match = /^((?:@[^\\/]+[\\/])?[^\\/]+)/.exec(request);
								if (!match) {
									requiredVersionWarning(
										"Unable to extract the package name from request."
									);
									return resolve();
								}
								packageName = match[0];
							}

							getDescriptionFile(
								compilation.inputFileSystem,
								context,
								["package.json"],
								(err, result) => {
									if (err) {
										requiredVersionWarning(
											`Unable to read description file: ${err}`
										);
										return resolve();
									}
									const { data, path: descriptionPath } = result;
									if (!data) {
										requiredVersionWarning(
											`Unable to find description file in ${context}.`
										);
										return resolve();
									}
									if (data.name === packageName) {
										// Package self-referencing
										return resolve();
									}
									const requiredVersion = getRequiredVersionFromDescriptionFile(
										data,
										packageName
									);
									if (typeof requiredVersion !== "string") {
										requiredVersionWarning(
											`Unable to find required version for "${packageName}" in description file (${descriptionPath}). It need to be in dependencies, devDependencies or peerDependencies.`
										);
										return resolve();
									}
									resolve(parseRange(requiredVersion));
								}
							);
						})
					]).then(([importResolved, requiredVersion]) => {
						return new ConsumeSharedModule(
							directFallback ? compiler.context : context,
							{
								...config,
								importResolved,
								import: importResolved ? config.import : undefined,
								requiredVersion
							}
						);
					});
				};

				normalModuleFactory.hooks.factorize.tapPromise(
					PLUGIN_NAME,
					({ context, request, dependencies }) =>
						// wait for resolving to be complete
						promise.then(() => {
							if (
								dependencies[0] instanceof ConsumeSharedFallbackDependency ||
								dependencies[0] instanceof ProvideForSharedDependency
							) {
								return;
							}
							const match = unresolvedConsumes.get(request);
							if (match !== undefined) {
								return createConsumeSharedModule(context, request, match);
							}
							for (const [prefix, options] of prefixedConsumes) {
								if (request.startsWith(prefix)) {
									const remainder = request.slice(prefix.length);
									return createConsumeSharedModule(context, request, {
										...options,
										import: options.import
											? options.import + remainder
											: undefined,
										shareKey: options.shareKey + remainder
									});
								}
							}
						})
				);
				normalModuleFactory.hooks.createModule.tapPromise(
					PLUGIN_NAME,
					({ resource }, { context, dependencies }) => {
						if (
							dependencies[0] instanceof ConsumeSharedFallbackDependency ||
							dependencies[0] instanceof ProvideForSharedDependency
						) {
							return Promise.resolve();
						}
						const options = resolvedConsumes.get(
							/** @type {string} */ (resource)
						);
						if (options !== undefined) {
							return createConsumeSharedModule(
								context,
								/** @type {string} */ (resource),
								options
							);
						}
						return Promise.resolve();
					}
				);
				compilation.hooks.additionalTreeRuntimeRequirements.tap(
					PLUGIN_NAME,
					(chunk, set) => {
						set.add(RuntimeGlobals.module);
						set.add(RuntimeGlobals.moduleCache);
						set.add(RuntimeGlobals.moduleFactoriesAddOnly);
						set.add(RuntimeGlobals.shareScopeMap);
						set.add(RuntimeGlobals.initializeSharing);
						set.add(RuntimeGlobals.hasOwnProperty);
						compilation.addRuntimeModule(
							chunk,
							new ConsumeSharedRuntimeModule(set)
						);
					}
				);
			}
		);
	}
}

module.exports = ConsumeSharedPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
const {
	parseVersionRuntimeCode,
	versionLtRuntimeCode,
	rangeToStringRuntimeCode,
	satisfyRuntimeCode
} = require("../util/semver");

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Chunk").ChunkId} ChunkId */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
/** @typedef {import("./ConsumeSharedModule")} ConsumeSharedModule */

class ConsumeSharedRuntimeModule extends RuntimeModule {
	/**
	 * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
	 */
	constructor(runtimeRequirements) {
		super("consumes", RuntimeModule.STAGE_ATTACH);
		this._runtimeRequirements = runtimeRequirements;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
		const { runtimeTemplate, codeGenerationResults } = compilation;
		/** @type {Record<ChunkId, (string | number)[]>} */
		const chunkToModuleMapping = {};
		/** @type {Map<string | number, Source>} */
		const moduleIdToSourceMapping = new Map();
		/** @type {(string | number)[]} */
		const initialConsumes = [];
		/**
		 *
		 * @param {Iterable<Module>} modules modules
		 * @param {Chunk} chunk the chunk
		 * @param {(string | number)[]} list list of ids
		 */
		const addModules = (modules, chunk, list) => {
			for (const m of modules) {
				const module = /** @type {ConsumeSharedModule} */ (m);
				const id = chunkGraph.getModuleId(module);
				list.push(id);
				moduleIdToSourceMapping.set(
					id,
					codeGenerationResults.getSource(
						module,
						chunk.runtime,
						"consume-shared"
					)
				);
			}
		};
		for (const chunk of /** @type {Chunk} */ (this.chunk).getAllAsyncChunks()) {
			const modules = chunkGraph.getChunkModulesIterableBySourceType(
				chunk,
				"consume-shared"
			);
			if (!modules) continue;
			addModules(
				modules,
				chunk,
				(chunkToModuleMapping[/** @type {ChunkId} */ (chunk.id)] = [])
			);
		}
		for (const chunk of /** @type {Chunk} */ (
			this.chunk
		).getAllInitialChunks()) {
			const modules = chunkGraph.getChunkModulesIterableBySourceType(
				chunk,
				"consume-shared"
			);
			if (!modules) continue;
			addModules(modules, chunk, initialConsumes);
		}
		if (moduleIdToSourceMapping.size === 0) return null;
		return Template.asString([
			parseVersionRuntimeCode(runtimeTemplate),
			versionLtRuntimeCode(runtimeTemplate),
			rangeToStringRuntimeCode(runtimeTemplate),
			satisfyRuntimeCode(runtimeTemplate),
			`var ensureExistence = ${runtimeTemplate.basicFunction("scopeName, key", [
				`var scope = ${RuntimeGlobals.shareScopeMap}[scopeName];`,
				`if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) throw new Error("Shared module " + key + " doesn't exist in shared scope " + scopeName);`,
				"return scope;"
			])};`,
			`var findVersion = ${runtimeTemplate.basicFunction("scope, key", [
				"var versions = scope[key];",
				`var key = Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
					"a, b",
					["return !a || versionLt(a, b) ? b : a;"]
				)}, 0);`,
				"return key && versions[key]"
			])};`,
			`var findSingletonVersionKey = ${runtimeTemplate.basicFunction(
				"scope, key",
				[
					"var versions = scope[key];",
					`return Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
						"a, b",
						["return !a || (!versions[a].loaded && versionLt(a, b)) ? b : a;"]
					)}, 0);`
				]
			)};`,
			`var getInvalidSingletonVersionMessage = ${runtimeTemplate.basicFunction(
				"scope, key, version, requiredVersion",
				[
					`return "Unsatisfied version " + version + " from " + (version && scope[key][version].from) + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"`
				]
			)};`,
			`var getSingleton = ${runtimeTemplate.basicFunction(
				"scope, scopeName, key, requiredVersion",
				[
					"var version = findSingletonVersionKey(scope, key);",
					"return get(scope[key][version]);"
				]
			)};`,
			`var getSingletonVersion = ${runtimeTemplate.basicFunction(
				"scope, scopeName, key, requiredVersion",
				[
					"var version = findSingletonVersionKey(scope, key);",
					"if (!satisfy(requiredVersion, version)) warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));",
					"return get(scope[key][version]);"
				]
			)};`,
			`var getStrictSingletonVersion = ${runtimeTemplate.basicFunction(
				"scope, scopeName, key, requiredVersion",
				[
					"var version = findSingletonVersionKey(scope, key);",
					"if (!satisfy(requiredVersion, version)) " +
						"throw new Error(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));",
					"return get(scope[key][version]);"
				]
			)};`,
			`var findValidVersion = ${runtimeTemplate.basicFunction(
				"scope, key, requiredVersion",
				[
					"var versions = scope[key];",
					`var key = Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
						"a, b",
						[
							"if (!satisfy(requiredVersion, b)) return a;",
							"return !a || versionLt(a, b) ? b : a;"
						]
					)}, 0);`,
					"return key && versions[key]"
				]
			)};`,
			`var getInvalidVersionMessage = ${runtimeTemplate.basicFunction(
				"scope, scopeName, key, requiredVersion",
				[
					"var versions = scope[key];",
					'return "No satisfying version (" + rangeToString(requiredVersion) + ") of shared module " + key + " found in shared scope " + scopeName + ".\\n" +',
					`\t"Available versions: " + Object.keys(versions).map(${runtimeTemplate.basicFunction(
						"key",
						['return key + " from " + versions[key].from;']
					)}).join(", ");`
				]
			)};`,
			`var getValidVersion = ${runtimeTemplate.basicFunction(
				"scope, scopeName, key, requiredVersion",
				[
					"var entry = findValidVersion(scope, key, requiredVersion);",
					"if(entry) return get(entry);",
					"throw new Error(getInvalidVersionMessage(scope, scopeName, key, requiredVersion));"
				]
			)};`,
			`var warn = ${
				compilation.outputOptions.ignoreBrowserWarnings
					? runtimeTemplate.basicFunction("", "")
					: runtimeTemplate.basicFunction("msg", [
							'if (typeof console !== "undefined" && console.warn) console.warn(msg);'
						])
			};`,
			`var warnInvalidVersion = ${runtimeTemplate.basicFunction(
				"scope, scopeName, key, requiredVersion",
				[
					"warn(getInvalidVersionMessage(scope, scopeName, key, requiredVersion));"
				]
			)};`,
			`var get = ${runtimeTemplate.basicFunction("entry", [
				"entry.loaded = 1;",
				"return entry.get()"
			])};`,
			`var init = ${runtimeTemplate.returningFunction(
				Template.asString([
					"function(scopeName, a, b, c) {",
					Template.indent([
						`var promise = ${RuntimeGlobals.initializeSharing}(scopeName);`,
						`if (promise && promise.then) return promise.then(fn.bind(fn, scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], a, b, c));`,
						`return fn(scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], a, b, c);`
					]),
					"}"
				]),
				"fn"
			)};`,
			"",
			`var load = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key",
				[
					"ensureExistence(scopeName, key);",
					"return get(findVersion(scope, key));"
				]
			)});`,
			`var loadFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, fallback",
				[
					`return scope && ${RuntimeGlobals.hasOwnProperty}(scope, key) ? get(findVersion(scope, key)) : fallback();`
				]
			)});`,
			`var loadVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, version",
				[
					"ensureExistence(scopeName, key);",
					"return get(findValidVersion(scope, key, version) || warnInvalidVersion(scope, scopeName, key, version) || findVersion(scope, key));"
				]
			)});`,
			`var loadSingleton = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key",
				[
					"ensureExistence(scopeName, key);",
					"return getSingleton(scope, scopeName, key);"
				]
			)});`,
			`var loadSingletonVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, version",
				[
					"ensureExistence(scopeName, key);",
					"return getSingletonVersion(scope, scopeName, key, version);"
				]
			)});`,
			`var loadStrictVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, version",
				[
					"ensureExistence(scopeName, key);",
					"return getValidVersion(scope, scopeName, key, version);"
				]
			)});`,
			`var loadStrictSingletonVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, version",
				[
					"ensureExistence(scopeName, key);",
					"return getStrictSingletonVersion(scope, scopeName, key, version);"
				]
			)});`,
			`var loadVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, version, fallback",
				[
					`if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
					"return get(findValidVersion(scope, key, version) || warnInvalidVersion(scope, scopeName, key, version) || findVersion(scope, key));"
				]
			)});`,
			`var loadSingletonFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, fallback",
				[
					`if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
					"return getSingleton(scope, scopeName, key);"
				]
			)});`,
			`var loadSingletonVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, version, fallback",
				[
					`if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
					"return getSingletonVersion(scope, scopeName, key, version);"
				]
			)});`,
			`var loadStrictVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, version, fallback",
				[
					`var entry = scope && ${RuntimeGlobals.hasOwnProperty}(scope, key) && findValidVersion(scope, key, version);`,
					`return entry ? get(entry) : fallback();`
				]
			)});`,
			`var loadStrictSingletonVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
				"scopeName, scope, key, version, fallback",
				[
					`if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
					"return getStrictSingletonVersion(scope, scopeName, key, version);"
				]
			)});`,
			"var installedModules = {};",
			"var moduleToHandlerMapping = {",
			Template.indent(
				Array.from(
					moduleIdToSourceMapping,
					([key, source]) => `${JSON.stringify(key)}: ${source.source()}`
				).join(",\n")
			),
			"};",

			initialConsumes.length > 0
				? Template.asString([
						`var initialConsumes = ${JSON.stringify(initialConsumes)};`,
						`initialConsumes.forEach(${runtimeTemplate.basicFunction("id", [
							`${
								RuntimeGlobals.moduleFactories
							}[id] = ${runtimeTemplate.basicFunction("module", [
								"// Handle case when module is used sync",
								"installedModules[id] = 0;",
								`delete ${RuntimeGlobals.moduleCache}[id];`,
								"var factory = moduleToHandlerMapping[id]();",
								'if(typeof factory !== "function") throw new Error("Shared module is not available for eager consumption: " + id);',
								`module.exports = factory();`
							])}`
						])});`
					])
				: "// no consumes in initial chunks",
			this._runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers)
				? Template.asString([
						`var chunkMapping = ${JSON.stringify(
							chunkToModuleMapping,
							null,
							"\t"
						)};`,
						"var startedInstallModules = {};",
						`${
							RuntimeGlobals.ensureChunkHandlers
						}.consumes = ${runtimeTemplate.basicFunction("chunkId, promises", [
							`if(${RuntimeGlobals.hasOwnProperty}(chunkMapping, chunkId)) {`,
							Template.indent([
								`chunkMapping[chunkId].forEach(${runtimeTemplate.basicFunction(
									"id",
									[
										`if(${RuntimeGlobals.hasOwnProperty}(installedModules, id)) return promises.push(installedModules[id]);`,
										"if(!startedInstallModules[id]) {",
										`var onFactory = ${runtimeTemplate.basicFunction(
											"factory",
											[
												"installedModules[id] = 0;",
												`${
													RuntimeGlobals.moduleFactories
												}[id] = ${runtimeTemplate.basicFunction("module", [
													`delete ${RuntimeGlobals.moduleCache}[id];`,
													"module.exports = factory();"
												])}`
											]
										)};`,
										"startedInstallModules[id] = true;",
										`var onError = ${runtimeTemplate.basicFunction("error", [
											"delete installedModules[id];",
											`${
												RuntimeGlobals.moduleFactories
											}[id] = ${runtimeTemplate.basicFunction("module", [
												`delete ${RuntimeGlobals.moduleCache}[id];`,
												"throw error;"
											])}`
										])};`,
										"try {",
										Template.indent([
											"var promise = moduleToHandlerMapping[id]();",
											"if(promise.then) {",
											Template.indent(
												"promises.push(installedModules[id] = promise.then(onFactory)['catch'](onError));"
											),
											"} else onFactory(promise);"
										]),
										"} catch(e) { onError(e); }",
										"}"
									]
								)});`
							]),
							"}"
						])}`
					])
				: "// no chunk loading of consumes"
		]);
	}
}

module.exports = ConsumeSharedRuntimeModule;

license: mit


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const ModuleDependency = require("../dependencies/ModuleDependency");
const makeSerializable = require("../util/makeSerializable");

class ProvideForSharedDependency extends ModuleDependency {
	/**
	 *
	 * @param {string} request request string
	 */
	constructor(request) {
		super(request);
	}

	get type() {
		return "provide module for shared";
	}

	get category() {
		return "esm";
	}
}

makeSerializable(
	ProvideForSharedDependency,
	"webpack/lib/sharing/ProvideForSharedDependency"
);

module.exports = ProvideForSharedDependency;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const Dependency = require("../Dependency");
const makeSerializable = require("../util/makeSerializable");

/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */

class ProvideSharedDependency extends Dependency {
	/**
	 * @param {string} shareScope share scope
	 * @param {string} name module name
	 * @param {string | false} version version
	 * @param {string} request request
	 * @param {boolean} eager true, if this is an eager dependency
	 */
	constructor(shareScope, name, version, request, eager) {
		super();
		this.shareScope = shareScope;
		this.name = name;
		this.version = version;
		this.request = request;
		this.eager = eager;
	}

	get type() {
		return "provide shared module";
	}

	/**
	 * @returns {string | null} an identifier to merge equal requests
	 */
	getResourceIdentifier() {
		return `provide module (${this.shareScope}) ${this.request} as ${
			this.name
		} @ ${this.version}${this.eager ? " (eager)" : ""}`;
	}

	/**
	 * @param {ObjectSerializerContext} context context
	 */
	serialize(context) {
		context.write(this.shareScope);
		context.write(this.name);
		context.write(this.request);
		context.write(this.version);
		context.write(this.eager);
		super.serialize(context);
	}

	/**
	 * @param {ObjectDeserializerContext} context context
	 * @returns {ProvideSharedDependency} deserialize fallback dependency
	 */
	static deserialize(context) {
		const { read } = context;
		const obj = new ProvideSharedDependency(
			read(),
			read(),
			read(),
			read(),
			read()
		);
		this.shareScope = context.read();
		obj.deserialize(context);
		return obj;
	}
}

makeSerializable(
	ProvideSharedDependency,
	"webpack/lib/sharing/ProvideSharedDependency"
);

module.exports = ProvideSharedDependency;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
*/

"use strict";

const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
const Module = require("../Module");
const { WEBPACK_MODULE_TYPE_PROVIDE } = require("../ModuleTypeConstants");
const RuntimeGlobals = require("../RuntimeGlobals");
const makeSerializable = require("../util/makeSerializable");
const ProvideForSharedDependency = require("./ProvideForSharedDependency");

/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../ChunkGroup")} ChunkGroup */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
/** @typedef {import("../Module").NeedBuildContext} NeedBuildContext */
/** @typedef {import("../Module").SourceTypes} SourceTypes */
/** @typedef {import("../RequestShortener")} RequestShortener */
/** @typedef {import("../ResolverFactory").ResolverWithOptions} ResolverWithOptions */
/** @typedef {import("../WebpackError")} WebpackError */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/** @typedef {import("../util/Hash")} Hash */
/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */

const TYPES = new Set(["share-init"]);

class ProvideSharedModule extends Module {
	/**
	 * @param {string} shareScope shared scope name
	 * @param {string} name shared key
	 * @param {string | false} version version
	 * @param {string} request request to the provided module
	 * @param {boolean} eager include the module in sync way
	 */
	constructor(shareScope, name, version, request, eager) {
		super(WEBPACK_MODULE_TYPE_PROVIDE);
		this._shareScope = shareScope;
		this._name = name;
		this._version = version;
		this._request = request;
		this._eager = eager;
	}

	/**
	 * @returns {string} a unique identifier of the module
	 */
	identifier() {
		return `provide module (${this._shareScope}) ${this._name}@${this._version} = ${this._request}`;
	}

	/**
	 * @param {RequestShortener} requestShortener the request shortener
	 * @returns {string} a user readable identifier of the module
	 */
	readableIdentifier(requestShortener) {
		return `provide shared module (${this._shareScope}) ${this._name}@${
			this._version
		} = ${requestShortener.shorten(this._request)}`;
	}

	/**
	 * @param {LibIdentOptions} options options
	 * @returns {string | null} an identifier for library inclusion
	 */
	libIdent(options) {
		return `${this.layer ? `(${this.layer})/` : ""}webpack/sharing/provide/${
			this._shareScope
		}/${this._name}`;
	}

	/**
	 * @param {NeedBuildContext} context context info
	 * @param {function((WebpackError | null)=, boolean=): void} callback callback function, returns true, if the module needs a rebuild
	 * @returns {void}
	 */
	needBuild(context, callback) {
		callback(null, !this.buildInfo);
	}

	/**
	 * @param {WebpackOptions} options webpack options
	 * @param {Compilation} compilation the compilation
	 * @param {ResolverWithOptions} resolver the resolver
	 * @param {InputFileSystem} fs the file system
	 * @param {function(WebpackError=): void} callback callback function
	 * @returns {void}
	 */
	build(options, compilation, resolver, fs, callback) {
		this.buildMeta = {};
		this.buildInfo = {
			strict: true
		};

		this.clearDependenciesAndBlocks();
		const dep = new ProvideForSharedDependency(this._request);
		if (this._eager) {
			this.addDependency(dep);
		} else {
			const block = new AsyncDependenciesBlock({});
			block.addDependency(dep);
			this.addBlock(block);
		}

		callback();
	}

	/**
	 * @param {string=} type the source type for which the size should be estimated
	 * @returns {number} the estimated size of the module (must be non-zero)
	 */
	size(type) {
		return 42;
	}

	/**
	 * @returns {SourceTypes} types available (do not mutate)
	 */
	getSourceTypes() {
		return TYPES;
	}

	/**
	 * @param {CodeGenerationContext} context context for code generation
	 * @returns {CodeGenerationResult} result
	 */
	codeGeneration({ runtimeTemplate, moduleGraph, chunkGraph }) {
		const runtimeRequirements = new Set([RuntimeGlobals.initializeSharing]);
		const code = `register(${JSON.stringify(this._name)}, ${JSON.stringify(
			this._version || "0"
		)}, ${
			this._eager
				? runtimeTemplate.syncModuleFactory({
						dependency: this.dependencies[0],
						chunkGraph,
						request: this._request,
						runtimeRequirements
					})
				: runtimeTemplate.asyncModuleFactory({
						block: this.blocks[0],
						chunkGraph,
						request: this._request,
						runtimeRequirements
					})
		}${this._eager ? ", 1" : ""});`;
		const sources = new Map();
		const data = new Map();
		data.set("share-init", [
			{
				shareScope: this._shareScope,
				initStage: 10,
				init: code
			}
		]);
		return { sources, data, runtimeRequirements };
	}

	/**
	 * @param {ObjectSerializerContext} context context
	 */
	serialize(context) {
		const { write } = context;
		write(this._shareScope);
		write(this._name);
		write(this._version);
		write(this._request);
		write(this._eager);
		super.serialize(context);
	}

	/**
	 * @param {ObjectDeserializerContext} context context
	 * @returns {ProvideSharedModule} deserialize fallback dependency
	 */
	static deserialize(context) {
		const { read } = context;
		const obj = new ProvideSharedModule(read(), read(), read(), read(), read());
		obj.deserialize(context);
		return obj;
	}
}

makeSerializable(
	ProvideSharedModule,
	"webpack/lib/sharing/ProvideSharedModule"
);

module.exports = ProvideSharedModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
*/

"use strict";

const ModuleFactory = require("../ModuleFactory");
const ProvideSharedModule = require("./ProvideSharedModule");

/** @typedef {import("../ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
/** @typedef {import("../ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
/** @typedef {import("./ProvideSharedDependency")} ProvideSharedDependency */

class ProvideSharedModuleFactory extends ModuleFactory {
	/**
	 * @param {ModuleFactoryCreateData} data data object
	 * @param {function((Error | null)=, ModuleFactoryResult=): void} callback callback
	 * @returns {void}
	 */
	create(data, callback) {
		const dep = /** @type {ProvideSharedDependency} */ (data.dependencies[0]);
		callback(null, {
			module: new ProvideSharedModule(
				dep.shareScope,
				dep.name,
				dep.version,
				dep.request,
				dep.eager
			)
		});
	}
}

module.exports = ProvideSharedModuleFactory;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
*/

"use strict";

const WebpackError = require("../WebpackError");
const { parseOptions } = require("../container/options");
const createSchemaValidation = require("../util/create-schema-validation");
const ProvideForSharedDependency = require("./ProvideForSharedDependency");
const ProvideSharedDependency = require("./ProvideSharedDependency");
const ProvideSharedModuleFactory = require("./ProvideSharedModuleFactory");

/** @typedef {import("../../declarations/plugins/sharing/ProvideSharedPlugin").ProvideSharedPluginOptions} ProvideSharedPluginOptions */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../NormalModuleFactory").NormalModuleCreateData} NormalModuleCreateData */

const validate = createSchemaValidation(
	require("../../schemas/plugins/sharing/ProvideSharedPlugin.check.js"),
	() => require("../../schemas/plugins/sharing/ProvideSharedPlugin.json"),
	{
		name: "Provide Shared Plugin",
		baseDataPath: "options"
	}
);

/**
 * @typedef {object} ProvideOptions
 * @property {string} shareKey
 * @property {string} shareScope
 * @property {string | undefined | false} version
 * @property {boolean} eager
 */

/** @typedef {Map<string, { config: ProvideOptions, version: string | undefined | false }>} ResolvedProvideMap */

class ProvideSharedPlugin {
	/**
	 * @param {ProvideSharedPluginOptions} options options
	 */
	constructor(options) {
		validate(options);

		this._provides = /** @type {[string, ProvideOptions][]} */ (
			parseOptions(
				options.provides,
				item => {
					if (Array.isArray(item))
						throw new Error("Unexpected array of provides");
					/** @type {ProvideOptions} */
					const result = {
						shareKey: item,
						version: undefined,
						shareScope: options.shareScope || "default",
						eager: false
					};
					return result;
				},
				item => ({
					shareKey: item.shareKey,
					version: item.version,
					shareScope: item.shareScope || options.shareScope || "default",
					eager: !!item.eager
				})
			)
		);
		this._provides.sort(([a], [b]) => {
			if (a < b) return -1;
			if (b < a) return 1;
			return 0;
		});
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		/** @type {WeakMap<Compilation, ResolvedProvideMap>} */
		const compilationData = new WeakMap();

		compiler.hooks.compilation.tap(
			"ProvideSharedPlugin",
			(compilation, { normalModuleFactory }) => {
				/** @type {ResolvedProvideMap} */
				const resolvedProvideMap = new Map();
				/** @type {Map<string, ProvideOptions>} */
				const matchProvides = new Map();
				/** @type {Map<string, ProvideOptions>} */
				const prefixMatchProvides = new Map();
				for (const [request, config] of this._provides) {
					if (/^(\/|[A-Za-z]:\\|\\\\|\.\.?(\/|$))/.test(request)) {
						// relative request
						resolvedProvideMap.set(request, {
							config,
							version: config.version
						});
					} else if (/^(\/|[A-Za-z]:\\|\\\\)/.test(request)) {
						// absolute path
						resolvedProvideMap.set(request, {
							config,
							version: config.version
						});
					} else if (request.endsWith("/")) {
						// module request prefix
						prefixMatchProvides.set(request, config);
					} else {
						// module request
						matchProvides.set(request, config);
					}
				}
				compilationData.set(compilation, resolvedProvideMap);
				/**
				 * @param {string} key key
				 * @param {ProvideOptions} config config
				 * @param {NormalModuleCreateData["resource"]} resource resource
				 * @param {NormalModuleCreateData["resourceResolveData"]} resourceResolveData resource resolve data
				 */
				const provideSharedModule = (
					key,
					config,
					resource,
					resourceResolveData
				) => {
					let version = config.version;
					if (version === undefined) {
						let details = "";
						if (!resourceResolveData) {
							details = `No resolve data provided from resolver.`;
						} else {
							const descriptionFileData =
								resourceResolveData.descriptionFileData;
							if (!descriptionFileData) {
								details =
									"No description file (usually package.json) found. Add description file with name and version, or manually specify version in shared config.";
							} else if (!descriptionFileData.version) {
								details = `No version in description file (usually package.json). Add version to description file ${resourceResolveData.descriptionFilePath}, or manually specify version in shared config.`;
							} else {
								version = descriptionFileData.version;
							}
						}
						if (!version) {
							const error = new WebpackError(
								`No version specified and unable to automatically determine one. ${details}`
							);
							error.file = `shared module ${key} -> ${resource}`;
							compilation.warnings.push(error);
						}
					}
					resolvedProvideMap.set(resource, {
						config,
						version
					});
				};
				normalModuleFactory.hooks.module.tap(
					"ProvideSharedPlugin",
					(module, { resource, resourceResolveData }, resolveData) => {
						if (resolvedProvideMap.has(/** @type {string} */ (resource))) {
							return module;
						}
						const { request } = resolveData;
						{
							const config = matchProvides.get(request);
							if (config !== undefined) {
								provideSharedModule(
									request,
									config,
									/** @type {string} */ (resource),
									resourceResolveData
								);
								resolveData.cacheable = false;
							}
						}
						for (const [prefix, config] of prefixMatchProvides) {
							if (request.startsWith(prefix)) {
								const remainder = request.slice(prefix.length);
								provideSharedModule(
									/** @type {string} */ (resource),
									{
										...config,
										shareKey: config.shareKey + remainder
									},
									/** @type {string} */ (resource),
									resourceResolveData
								);
								resolveData.cacheable = false;
							}
						}
						return module;
					}
				);
			}
		);
		compiler.hooks.finishMake.tapPromise("ProvideSharedPlugin", compilation => {
			const resolvedProvideMap = compilationData.get(compilation);
			if (!resolvedProvideMap) return Promise.resolve();
			return Promise.all(
				Array.from(
					resolvedProvideMap,
					([resource, { config, version }]) =>
						new Promise((resolve, reject) => {
							compilation.addInclude(
								compiler.context,
								new ProvideSharedDependency(
									config.shareScope,
									config.shareKey,
									version || false,
									resource,
									config.eager
								),
								{
									name: undefined
								},
								err => {
									if (err) return reject(err);
									resolve(null);
								}
							);
						})
				)
			).then(() => {});
		});

		compiler.hooks.compilation.tap(
			"ProvideSharedPlugin",
			(compilation, { normalModuleFactory }) => {
				compilation.dependencyFactories.set(
					ProvideForSharedDependency,
					normalModuleFactory
				);

				compilation.dependencyFactories.set(
					ProvideSharedDependency,
					new ProvideSharedModuleFactory()
				);
			}
		);
	}
}

module.exports = ProvideSharedPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
*/

"use strict";

const { parseOptions } = require("../container/options");
const ConsumeSharedPlugin = require("./ConsumeSharedPlugin");
const ProvideSharedPlugin = require("./ProvideSharedPlugin");
const { isRequiredVersion } = require("./utils");

/** @typedef {import("../../declarations/plugins/sharing/ConsumeSharedPlugin").ConsumeSharedPluginOptions} ConsumeSharedPluginOptions */
/** @typedef {import("../../declarations/plugins/sharing/ConsumeSharedPlugin").ConsumesConfig} ConsumesConfig */
/** @typedef {import("../../declarations/plugins/sharing/ProvideSharedPlugin").ProvideSharedPluginOptions} ProvideSharedPluginOptions */
/** @typedef {import("../../declarations/plugins/sharing/ProvideSharedPlugin").ProvidesConfig} ProvidesConfig */
/** @typedef {import("../../declarations/plugins/sharing/SharePlugin").SharePluginOptions} SharePluginOptions */
/** @typedef {import("../../declarations/plugins/sharing/SharePlugin").SharedConfig} SharedConfig */
/** @typedef {import("../Compiler")} Compiler */

class SharePlugin {
	/**
	 * @param {SharePluginOptions} options options
	 */
	constructor(options) {
		/** @type {[string, SharedConfig][]} */
		const sharedOptions = parseOptions(
			options.shared,
			(item, key) => {
				if (typeof item !== "string")
					throw new Error("Unexpected array in shared");
				/** @type {SharedConfig} */
				const config =
					item === key || !isRequiredVersion(item)
						? {
								import: item
							}
						: {
								import: key,
								requiredVersion: item
							};
				return config;
			},
			item => item
		);
		/** @type {Record<string, ConsumesConfig>[]} */
		const consumes = sharedOptions.map(([key, options]) => ({
			[key]: {
				import: options.import,
				shareKey: options.shareKey || key,
				shareScope: options.shareScope,
				requiredVersion: options.requiredVersion,
				strictVersion: options.strictVersion,
				singleton: options.singleton,
				packageName: options.packageName,
				eager: options.eager
			}
		}));
		/** @type {Record<string, ProvidesConfig>[]} */
		const provides = sharedOptions
			.filter(([, options]) => options.import !== false)
			.map(([key, options]) => ({
				[options.import || key]: {
					shareKey: options.shareKey || key,
					shareScope: options.shareScope,
					version: options.version,
					eager: options.eager
				}
			}));
		this._shareScope = options.shareScope;
		this._consumes = consumes;
		this._provides = provides;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		new ConsumeSharedPlugin({
			shareScope: this._shareScope,
			consumes: this._consumes
		}).apply(compiler);
		new ProvideSharedPlugin({
			shareScope: this._shareScope,
			provides: this._provides
		}).apply(compiler);
	}
}

module.exports = SharePlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
const {
	compareModulesByIdentifier,
	compareStrings
} = require("../util/comparators");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */

class ShareRuntimeModule extends RuntimeModule {
	constructor() {
		super("sharing");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const {
			runtimeTemplate,
			codeGenerationResults,
			outputOptions: { uniqueName, ignoreBrowserWarnings }
		} = compilation;
		const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
		/** @type {Map<string, Map<number, Set<string>>>} */
		const initCodePerScope = new Map();
		for (const chunk of /** @type {Chunk} */ (
			this.chunk
		).getAllReferencedChunks()) {
			const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
				chunk,
				"share-init",
				compareModulesByIdentifier
			);
			if (!modules) continue;
			for (const m of modules) {
				const data = codeGenerationResults.getData(
					m,
					chunk.runtime,
					"share-init"
				);
				if (!data) continue;
				for (const item of data) {
					const { shareScope, initStage, init } = item;
					let stages = initCodePerScope.get(shareScope);
					if (stages === undefined) {
						initCodePerScope.set(shareScope, (stages = new Map()));
					}
					let list = stages.get(initStage || 0);
					if (list === undefined) {
						stages.set(initStage || 0, (list = new Set()));
					}
					list.add(init);
				}
			}
		}
		return Template.asString([
			`${RuntimeGlobals.shareScopeMap} = {};`,
			"var initPromises = {};",
			"var initTokens = {};",
			`${RuntimeGlobals.initializeSharing} = ${runtimeTemplate.basicFunction(
				"name, initScope",
				[
					"if(!initScope) initScope = [];",
					"// handling circular init calls",
					"var initToken = initTokens[name];",
					"if(!initToken) initToken = initTokens[name] = {};",
					"if(initScope.indexOf(initToken) >= 0) return;",
					"initScope.push(initToken);",
					"// only runs once",
					"if(initPromises[name]) return initPromises[name];",
					"// creates a new share scope if needed",
					`if(!${RuntimeGlobals.hasOwnProperty}(${RuntimeGlobals.shareScopeMap}, name)) ${RuntimeGlobals.shareScopeMap}[name] = {};`,
					"// runs all init snippets from all modules reachable",
					`var scope = ${RuntimeGlobals.shareScopeMap}[name];`,
					`var warn = ${
						ignoreBrowserWarnings
							? runtimeTemplate.basicFunction("", "")
							: runtimeTemplate.basicFunction("msg", [
									'if (typeof console !== "undefined" && console.warn) console.warn(msg);'
								])
					};`,
					`var uniqueName = ${JSON.stringify(uniqueName || undefined)};`,
					`var register = ${runtimeTemplate.basicFunction(
						"name, version, factory, eager",
						[
							"var versions = scope[name] = scope[name] || {};",
							"var activeVersion = versions[version];",
							"if(!activeVersion || (!activeVersion.loaded && (!eager != !activeVersion.eager ? eager : uniqueName > activeVersion.from))) versions[version] = { get: factory, from: uniqueName, eager: !!eager };"
						]
					)};`,
					`var initExternal = ${runtimeTemplate.basicFunction("id", [
						`var handleError = ${runtimeTemplate.expressionFunction(
							'warn("Initialization of sharing external failed: " + err)',
							"err"
						)};`,
						"try {",
						Template.indent([
							`var module = ${RuntimeGlobals.require}(id);`,
							"if(!module) return;",
							`var initFn = ${runtimeTemplate.returningFunction(
								`module && module.init && module.init(${RuntimeGlobals.shareScopeMap}[name], initScope)`,
								"module"
							)}`,
							"if(module.then) return promises.push(module.then(initFn, handleError));",
							"var initResult = initFn(module);",
							"if(initResult && initResult.then) return promises.push(initResult['catch'](handleError));"
						]),
						"} catch(err) { handleError(err); }"
					])}`,
					"var promises = [];",
					"switch(name) {",
					...Array.from(initCodePerScope)
						.sort(([a], [b]) => compareStrings(a, b))
						.map(([name, stages]) =>
							Template.indent([
								`case ${JSON.stringify(name)}: {`,
								Template.indent(
									Array.from(stages)
										.sort(([a], [b]) => a - b)
										.map(([, initCode]) =>
											Template.asString(Array.from(initCode))
										)
								),
								"}",
								"break;"
							])
						),
					"}",
					"if(!promises.length) return initPromises[name] = 1;",
					`return initPromises[name] = Promise.all(promises).then(${runtimeTemplate.returningFunction(
						"initPromises[name] = 1"
					)});`
				]
			)};`
		]);
	}
}

module.exports = ShareRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const ModuleNotFoundError = require("../ModuleNotFoundError");
const LazySet = require("../util/LazySet");

/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../ResolverFactory").ResolveOptionsWithDependencyType} ResolveOptionsWithDependencyType */

/**
 * @template T
 * @typedef {object} MatchedConfigs
 * @property {Map<string, T>} resolved
 * @property {Map<string, T>} unresolved
 * @property {Map<string, T>} prefixed
 */

/** @type {ResolveOptionsWithDependencyType} */
const RESOLVE_OPTIONS = { dependencyType: "esm" };

/**
 * @template T
 * @param {Compilation} compilation the compilation
 * @param {[string, T][]} configs to be processed configs
 * @returns {Promise<MatchedConfigs<T>>} resolved matchers
 */
exports.resolveMatchedConfigs = (compilation, configs) => {
	/** @type {Map<string, T>} */
	const resolved = new Map();
	/** @type {Map<string, T>} */
	const unresolved = new Map();
	/** @type {Map<string, T>} */
	const prefixed = new Map();
	const resolveContext = {
		/** @type {LazySet<string>} */
		fileDependencies: new LazySet(),
		/** @type {LazySet<string>} */
		contextDependencies: new LazySet(),
		/** @type {LazySet<string>} */
		missingDependencies: new LazySet()
	};
	const resolver = compilation.resolverFactory.get("normal", RESOLVE_OPTIONS);
	const context = compilation.compiler.context;

	return Promise.all(
		configs.map(([request, config]) => {
			if (/^\.\.?(\/|$)/.test(request)) {
				// relative request
				return new Promise(resolve => {
					resolver.resolve(
						{},
						context,
						request,
						resolveContext,
						(err, result) => {
							if (err || result === false) {
								err = err || new Error(`Can't resolve ${request}`);
								compilation.errors.push(
									new ModuleNotFoundError(null, err, {
										name: `shared module ${request}`
									})
								);
								return resolve(null);
							}
							resolved.set(/** @type {string} */ (result), config);
							resolve(null);
						}
					);
				});
			} else if (/^(\/|[A-Za-z]:\\|\\\\)/.test(request)) {
				// absolute path
				resolved.set(request, config);
			} else if (request.endsWith("/")) {
				// module request prefix
				prefixed.set(request, config);
			} else {
				// module request
				unresolved.set(request, config);
			}
		})
	).then(() => {
		compilation.contextDependencies.addAll(resolveContext.contextDependencies);
		compilation.fileDependencies.addAll(resolveContext.fileDependencies);
		compilation.missingDependencies.addAll(resolveContext.missingDependencies);
		return { resolved, unresolved, prefixed };
	});
};


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { join, dirname, readJson } = require("../util/fs");

/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
/** @typedef {import("../util/fs").JsonObject} JsonObject */
/** @typedef {import("../util/fs").JsonPrimitive} JsonPrimitive */

// Extreme shorthand only for github. eg: foo/bar
const RE_URL_GITHUB_EXTREME_SHORT = /^[^/@:.\s][^/@:\s]*\/[^@:\s]*[^/@:\s]#\S+/;

// Short url with specific protocol. eg: github:foo/bar
const RE_GIT_URL_SHORT = /^(github|gitlab|bitbucket|gist):\/?[^/.]+\/?/i;

// Currently supported protocols
const RE_PROTOCOL =
	/^((git\+)?(ssh|https?|file)|git|github|gitlab|bitbucket|gist):$/i;

// Has custom protocol
const RE_CUSTOM_PROTOCOL = /^((git\+)?(ssh|https?|file)|git):\/\//i;

// Valid hash format for npm / yarn ...
const RE_URL_HASH_VERSION = /#(?:semver:)?(.+)/;

// Simple hostname validate
const RE_HOSTNAME = /^(?:[^/.]+(\.[^/]+)+|localhost)$/;

// For hostname with colon. eg: ssh://user@github.com:foo/bar
const RE_HOSTNAME_WITH_COLON =
	/([^/@#:.]+(?:\.[^/@#:.]+)+|localhost):([^#/0-9]+)/;

// Reg for url without protocol
const RE_NO_PROTOCOL = /^([^/@#:.]+(?:\.[^/@#:.]+)+)/;

// RegExp for version string
const VERSION_PATTERN_REGEXP = /^([\d^=v<>~]|[*xX]$)/;

// Specific protocol for short url without normal hostname
const PROTOCOLS_FOR_SHORT = [
	"github:",
	"gitlab:",
	"bitbucket:",
	"gist:",
	"file:"
];

// Default protocol for git url
const DEF_GIT_PROTOCOL = "git+ssh://";

// thanks to https://github.com/npm/hosted-git-info/blob/latest/git-host-info.js
const extractCommithashByDomain = {
	/**
	 * @param {string} pathname pathname
	 * @param {string} hash hash
	 * @returns {string | undefined} hash
	 */
	"github.com": (pathname, hash) => {
		let [, user, project, type, commithash] = pathname.split("/", 5);
		if (type && type !== "tree") {
			return;
		}

		if (!type) {
			commithash = hash;
		} else {
			commithash = "#" + commithash;
		}

		if (project && project.endsWith(".git")) {
			project = project.slice(0, -4);
		}

		if (!user || !project) {
			return;
		}

		return commithash;
	},
	/**
	 * @param {string} pathname pathname
	 * @param {string} hash hash
	 * @returns {string | undefined} hash
	 */
	"gitlab.com": (pathname, hash) => {
		const path = pathname.slice(1);
		if (path.includes("/-/") || path.includes("/archive.tar.gz")) {
			return;
		}

		const segments = path.split("/");
		let project = /** @type {string} */ (segments.pop());
		if (project.endsWith(".git")) {
			project = project.slice(0, -4);
		}

		const user = segments.join("/");
		if (!user || !project) {
			return;
		}

		return hash;
	},
	/**
	 * @param {string} pathname pathname
	 * @param {string} hash hash
	 * @returns {string | undefined} hash
	 */
	"bitbucket.org": (pathname, hash) => {
		let [, user, project, aux] = pathname.split("/", 4);
		if (["get"].includes(aux)) {
			return;
		}

		if (project && project.endsWith(".git")) {
			project = project.slice(0, -4);
		}

		if (!user || !project) {
			return;
		}

		return hash;
	},
	/**
	 * @param {string} pathname pathname
	 * @param {string} hash hash
	 * @returns {string | undefined} hash
	 */
	"gist.github.com": (pathname, hash) => {
		let [, user, project, aux] = pathname.split("/", 4);
		if (aux === "raw") {
			return;
		}

		if (!project) {
			if (!user) {
				return;
			}

			project = user;
		}

		if (project.endsWith(".git")) {
			project = project.slice(0, -4);
		}

		return hash;
	}
};

/**
 * extract commit hash from parsed url
 *
 * @inner
 * @param {URL} urlParsed parsed url
 * @returns {string} commithash
 */
function getCommithash(urlParsed) {
	let { hostname, pathname, hash } = urlParsed;
	hostname = hostname.replace(/^www\./, "");

	try {
		hash = decodeURIComponent(hash);
		// eslint-disable-next-line no-empty
	} catch (e) {}

	if (
		extractCommithashByDomain[
			/** @type {keyof extractCommithashByDomain} */ (hostname)
		]
	) {
		return (
			extractCommithashByDomain[
				/** @type {keyof extractCommithashByDomain} */ (hostname)
			](pathname, hash) || ""
		);
	}

	return hash;
}

/**
 * make url right for URL parse
 *
 * @inner
 * @param {string} gitUrl git url
 * @returns {string} fixed url
 */
function correctUrl(gitUrl) {
	// like:
	// proto://hostname.com:user/repo -> proto://hostname.com/user/repo
	return gitUrl.replace(RE_HOSTNAME_WITH_COLON, "$1/$2");
}

/**
 * make url protocol right for URL parse
 *
 * @inner
 * @param {string} gitUrl git url
 * @returns {string} fixed url
 */
function correctProtocol(gitUrl) {
	// eg: github:foo/bar#v1.0. Should not add double slash, in case of error parsed `pathname`
	if (RE_GIT_URL_SHORT.test(gitUrl)) {
		return gitUrl;
	}

	// eg: user@github.com:foo/bar
	if (!RE_CUSTOM_PROTOCOL.test(gitUrl)) {
		return `${DEF_GIT_PROTOCOL}${gitUrl}`;
	}

	return gitUrl;
}

/**
 * extract git dep version from hash
 *
 * @inner
 * @param {string} hash hash
 * @returns {string} git dep version
 */
function getVersionFromHash(hash) {
	const matched = hash.match(RE_URL_HASH_VERSION);

	return (matched && matched[1]) || "";
}

/**
 * if string can be decoded
 *
 * @inner
 * @param {string} str str to be checked
 * @returns {boolean} if can be decoded
 */
function canBeDecoded(str) {
	try {
		decodeURIComponent(str);
	} catch (e) {
		return false;
	}

	return true;
}

/**
 * get right dep version from git url
 *
 * @inner
 * @param {string} gitUrl git url
 * @returns {string} dep version
 */
function getGitUrlVersion(gitUrl) {
	let oriGitUrl = gitUrl;
	// github extreme shorthand
	if (RE_URL_GITHUB_EXTREME_SHORT.test(gitUrl)) {
		gitUrl = "github:" + gitUrl;
	} else {
		gitUrl = correctProtocol(gitUrl);
	}

	gitUrl = correctUrl(gitUrl);

	let parsed;
	try {
		parsed = new URL(gitUrl);
		// eslint-disable-next-line no-empty
	} catch (e) {}

	if (!parsed) {
		return "";
	}

	const { protocol, hostname, pathname, username, password } = parsed;
	if (!RE_PROTOCOL.test(protocol)) {
		return "";
	}

	// pathname shouldn't be empty or URL malformed
	if (!pathname || !canBeDecoded(pathname)) {
		return "";
	}

	// without protocol, there should have auth info
	if (RE_NO_PROTOCOL.test(oriGitUrl) && !username && !password) {
		return "";
	}

	if (!PROTOCOLS_FOR_SHORT.includes(protocol.toLowerCase())) {
		if (!RE_HOSTNAME.test(hostname)) {
			return "";
		}

		const commithash = getCommithash(parsed);
		return getVersionFromHash(commithash) || commithash;
	}

	// for protocol short
	return getVersionFromHash(gitUrl);
}

/**
 * @param {string} str maybe required version
 * @returns {boolean} true, if it looks like a version
 */
function isRequiredVersion(str) {
	return VERSION_PATTERN_REGEXP.test(str);
}

exports.isRequiredVersion = isRequiredVersion;

/**
 * @see https://docs.npmjs.com/cli/v7/configuring-npm/package-json#urls-as-dependencies
 * @param {string} versionDesc version to be normalized
 * @returns {string} normalized version
 */
function normalizeVersion(versionDesc) {
	versionDesc = (versionDesc && versionDesc.trim()) || "";

	if (isRequiredVersion(versionDesc)) {
		return versionDesc;
	}

	// add handle for URL Dependencies
	return getGitUrlVersion(versionDesc.toLowerCase());
}

exports.normalizeVersion = normalizeVersion;

/**
 *
 * @param {InputFileSystem} fs file system
 * @param {string} directory directory to start looking into
 * @param {string[]} descriptionFiles possible description filenames
 * @param {function((Error | null)=, {data: object, path: string}=): void} callback callback
 */
const getDescriptionFile = (fs, directory, descriptionFiles, callback) => {
	let i = 0;
	const tryLoadCurrent = () => {
		if (i >= descriptionFiles.length) {
			const parentDirectory = dirname(fs, directory);
			if (!parentDirectory || parentDirectory === directory) return callback();
			return getDescriptionFile(
				fs,
				parentDirectory,
				descriptionFiles,
				callback
			);
		}
		const filePath = join(fs, directory, descriptionFiles[i]);
		readJson(fs, filePath, (err, data) => {
			if (err) {
				if ("code" in err && err.code === "ENOENT") {
					i++;
					return tryLoadCurrent();
				}
				return callback(err);
			}
			if (!data || typeof data !== "object" || Array.isArray(data)) {
				return callback(
					new Error(`Description file ${filePath} is not an object`)
				);
			}
			callback(null, { data, path: filePath });
		});
	};
	tryLoadCurrent();
};
exports.getDescriptionFile = getDescriptionFile;

/**
 *
 * @param {JsonObject} data description file data i.e.: package.json
 * @param {string} packageName name of the dependency
 * @returns {string | undefined} normalized version
 */
const getRequiredVersionFromDescriptionFile = (data, packageName) => {
	const dependencyTypes = [
		"optionalDependencies",
		"dependencies",
		"peerDependencies",
		"devDependencies"
	];

	for (const dependencyType of dependencyTypes) {
		const dependency = /** @type {JsonObject} */ (data[dependencyType]);
		if (
			dependency &&
			typeof dependency === "object" &&
			packageName in dependency
		) {
			return normalizeVersion(
				/** @type {Exclude<JsonPrimitive, null | boolean| number>} */ (
					dependency[packageName]
				)
			);
		}
	}
};
exports.getRequiredVersionFromDescriptionFile =
	getRequiredVersionFromDescriptionFile;