diff options
Diffstat (limited to 'node_modules/webpack/lib/sharing')
13 files changed, 2310 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/sharing/ConsumeSharedFallbackDependency.js b/node_modules/webpack/lib/sharing/ConsumeSharedFallbackDependency.js new file mode 100644 index 00000000..bd6eefef --- /dev/null +++ b/node_modules/webpack/lib/sharing/ConsumeSharedFallbackDependency.js @@ -0,0 +1,33 @@ +/* + 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 ConsumeSharedFallbackDependency extends ModuleDependency { + /** + * @param {string} request the request + */ + constructor(request) { + super(request); + } + + get type() { + return "consume shared fallback"; + } + + get category() { + return "esm"; + } +} + +makeSerializable( + ConsumeSharedFallbackDependency, + "webpack/lib/sharing/ConsumeSharedFallbackDependency" +); + +module.exports = ConsumeSharedFallbackDependency; diff --git a/node_modules/webpack/lib/sharing/ConsumeSharedModule.js b/node_modules/webpack/lib/sharing/ConsumeSharedModule.js new file mode 100644 index 00000000..0ad41d31 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ConsumeSharedModule.js @@ -0,0 +1,262 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const { RawSource } = require("webpack-sources"); +const AsyncDependenciesBlock = require("../AsyncDependenciesBlock"); +const Module = require("../Module"); +const { + WEBPACK_MODULE_TYPE_CONSUME_SHARED_MODULE +} = require("../ModuleTypeConstants"); +const RuntimeGlobals = require("../RuntimeGlobals"); +const makeSerializable = require("../util/makeSerializable"); +const { rangeToString, stringifyHoley } = require("../util/semver"); +const ConsumeSharedFallbackDependency = require("./ConsumeSharedFallbackDependency"); + +/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */ +/** @typedef {import("../ChunkGraph")} ChunkGraph */ +/** @typedef {import("../ChunkGroup")} ChunkGroup */ +/** @typedef {import("../Compilation")} Compilation */ +/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */ +/** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */ +/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */ +/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */ +/** @typedef {import("../Module").NeedBuildContext} NeedBuildContext */ +/** @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 */ +/** @typedef {import("../util/semver").SemVerRange} SemVerRange */ + +/** + * @typedef {Object} ConsumeOptions + * @property {string=} import fallback request + * @property {string=} importResolved resolved fallback request + * @property {string} shareKey global share key + * @property {string} shareScope share scope + * @property {SemVerRange | false | undefined} requiredVersion version requirement + * @property {string} packageName package name to determine required version automatically + * @property {boolean} strictVersion don't use shared version even if version isn't valid + * @property {boolean} singleton use single global version + * @property {boolean} eager include the fallback module in a sync way + */ + +const TYPES = new Set(["consume-shared"]); + +class ConsumeSharedModule extends Module { + /** + * @param {string} context context + * @param {ConsumeOptions} options consume options + */ + constructor(context, options) { + super(WEBPACK_MODULE_TYPE_CONSUME_SHARED_MODULE, context); + this.options = options; + } + + /** + * @returns {string} a unique identifier of the module + */ + identifier() { + const { + shareKey, + shareScope, + importResolved, + requiredVersion, + strictVersion, + singleton, + eager + } = this.options; + return `${WEBPACK_MODULE_TYPE_CONSUME_SHARED_MODULE}|${shareScope}|${shareKey}|${ + requiredVersion && rangeToString(requiredVersion) + }|${strictVersion}|${importResolved}|${singleton}|${eager}`; + } + + /** + * @param {RequestShortener} requestShortener the request shortener + * @returns {string} a user readable identifier of the module + */ + readableIdentifier(requestShortener) { + const { + shareKey, + shareScope, + importResolved, + requiredVersion, + strictVersion, + singleton, + eager + } = this.options; + return `consume shared module (${shareScope}) ${shareKey}@${ + requiredVersion ? rangeToString(requiredVersion) : "*" + }${strictVersion ? " (strict)" : ""}${singleton ? " (singleton)" : ""}${ + importResolved + ? ` (fallback: ${requestShortener.shorten(importResolved)})` + : "" + }${eager ? " (eager)" : ""}`; + } + + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ + libIdent(options) { + const { shareKey, shareScope, import: request } = this.options; + return `${ + this.layer ? `(${this.layer})/` : "" + }webpack/sharing/consume/${shareScope}/${shareKey}${ + request ? `/${request}` : "" + }`; + } + + /** + * @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 = {}; + if (this.options.import) { + const dep = new ConsumeSharedFallbackDependency(this.options.import); + if (this.options.eager) { + this.addDependency(dep); + } else { + const block = new AsyncDependenciesBlock({}); + block.addDependency(dep); + this.addBlock(block); + } + } + callback(); + } + + /** + * @returns {Set<string>} types available (do not mutate) + */ + getSourceTypes() { + return TYPES; + } + + /** + * @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; + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @param {UpdateHashContext} context context + * @returns {void} + */ + updateHash(hash, context) { + hash.update(JSON.stringify(this.options)); + super.updateHash(hash, context); + } + + /** + * @param {CodeGenerationContext} context context for code generation + * @returns {CodeGenerationResult} result + */ + codeGeneration({ chunkGraph, moduleGraph, runtimeTemplate }) { + const runtimeRequirements = new Set([RuntimeGlobals.shareScopeMap]); + const { + shareScope, + shareKey, + strictVersion, + requiredVersion, + import: request, + singleton, + eager + } = this.options; + let fallbackCode; + if (request) { + if (eager) { + const dep = this.dependencies[0]; + fallbackCode = runtimeTemplate.syncModuleFactory({ + dependency: dep, + chunkGraph, + runtimeRequirements, + request: this.options.import + }); + } else { + const block = this.blocks[0]; + fallbackCode = runtimeTemplate.asyncModuleFactory({ + block, + chunkGraph, + runtimeRequirements, + request: this.options.import + }); + } + } + let fn = "load"; + const args = [JSON.stringify(shareScope), JSON.stringify(shareKey)]; + if (requiredVersion) { + if (strictVersion) { + fn += "Strict"; + } + if (singleton) { + fn += "Singleton"; + } + args.push(stringifyHoley(requiredVersion)); + fn += "VersionCheck"; + } else { + if (singleton) { + fn += "Singleton"; + } + } + if (fallbackCode) { + fn += "Fallback"; + args.push(fallbackCode); + } + const code = runtimeTemplate.returningFunction(`${fn}(${args.join(", ")})`); + const sources = new Map(); + sources.set("consume-shared", new RawSource(code)); + return { + runtimeRequirements, + sources + }; + } + + /** + * @param {ObjectSerializerContext} context context + */ + serialize(context) { + const { write } = context; + write(this.options); + super.serialize(context); + } + + /** + * @param {ObjectDeserializerContext} context context + */ + deserialize(context) { + const { read } = context; + this.options = read(); + super.deserialize(context); + } +} + +makeSerializable( + ConsumeSharedModule, + "webpack/lib/sharing/ConsumeSharedModule" +); + +module.exports = ConsumeSharedModule; diff --git a/node_modules/webpack/lib/sharing/ConsumeSharedPlugin.js b/node_modules/webpack/lib/sharing/ConsumeSharedPlugin.js new file mode 100644 index 00000000..1d8eb3eb --- /dev/null +++ b/node_modules/webpack/lib/sharing/ConsumeSharedPlugin.js @@ -0,0 +1,323 @@ +/* + 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 + ); + + let unresolvedConsumes, resolvedConsumes, 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) => { + 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(resource); + if (options !== undefined) { + return createConsumeSharedModule(context, 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; diff --git a/node_modules/webpack/lib/sharing/ConsumeSharedRuntimeModule.js b/node_modules/webpack/lib/sharing/ConsumeSharedRuntimeModule.js new file mode 100644 index 00000000..355adcd7 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ConsumeSharedRuntimeModule.js @@ -0,0 +1,375 @@ +/* + 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("../ChunkGraph")} ChunkGraph */ +/** @typedef {import("../Compilation")} Compilation */ +/** @typedef {import("../Module")} Module */ +/** @typedef {import("./ConsumeSharedModule")} ConsumeSharedModule */ + +class ConsumeSharedRuntimeModule extends RuntimeModule { + /** + * @param {ReadonlySet<string>} 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; + 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[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" + )};`, + `${ + 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]);`, + `var onFactory = ${runtimeTemplate.basicFunction( + "factory", + [ + "installedModules[id] = 0;", + `${ + RuntimeGlobals.moduleFactories + }[id] = ${runtimeTemplate.basicFunction("module", [ + `delete ${RuntimeGlobals.moduleCache}[id];`, + "module.exports = factory();" + ])}` + ] + )};`, + `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; diff --git a/node_modules/webpack/lib/sharing/ProvideForSharedDependency.js b/node_modules/webpack/lib/sharing/ProvideForSharedDependency.js new file mode 100644 index 00000000..5177f613 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ProvideForSharedDependency.js @@ -0,0 +1,34 @@ +/* + 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; diff --git a/node_modules/webpack/lib/sharing/ProvideSharedDependency.js b/node_modules/webpack/lib/sharing/ProvideSharedDependency.js new file mode 100644 index 00000000..2df18a61 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ProvideSharedDependency.js @@ -0,0 +1,80 @@ +/* + 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; diff --git a/node_modules/webpack/lib/sharing/ProvideSharedModule.js b/node_modules/webpack/lib/sharing/ProvideSharedModule.js new file mode 100644 index 00000000..ae8e38dc --- /dev/null +++ b/node_modules/webpack/lib/sharing/ProvideSharedModule.js @@ -0,0 +1,194 @@ +/* + 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("../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 {Set<string>} 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; diff --git a/node_modules/webpack/lib/sharing/ProvideSharedModuleFactory.js b/node_modules/webpack/lib/sharing/ProvideSharedModuleFactory.js new file mode 100644 index 00000000..d5bcc829 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ProvideSharedModuleFactory.js @@ -0,0 +1,35 @@ +/* + 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; diff --git a/node_modules/webpack/lib/sharing/ProvideSharedPlugin.js b/node_modules/webpack/lib/sharing/ProvideSharedPlugin.js new file mode 100644 index 00000000..5f2eb650 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ProvideSharedPlugin.js @@ -0,0 +1,237 @@ +/* + 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 */ + +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); + 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(resource)) { + return module; + } + const { request } = resolveData; + { + const config = matchProvides.get(request); + if (config !== undefined) { + provideSharedModule( + request, + config, + resource, + resourceResolveData + ); + resolveData.cacheable = false; + } + } + for (const [prefix, config] of prefixMatchProvides) { + if (request.startsWith(prefix)) { + const remainder = request.slice(prefix.length); + provideSharedModule( + resource, + { + ...config, + shareKey: config.shareKey + remainder + }, + 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(); + } + ); + }) + ) + ).then(() => {}); + }); + + compiler.hooks.compilation.tap( + "ProvideSharedPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + ProvideForSharedDependency, + normalModuleFactory + ); + + compilation.dependencyFactories.set( + ProvideSharedDependency, + new ProvideSharedModuleFactory() + ); + } + ); + } +} + +module.exports = ProvideSharedPlugin; diff --git a/node_modules/webpack/lib/sharing/SharePlugin.js b/node_modules/webpack/lib/sharing/SharePlugin.js new file mode 100644 index 00000000..ccbd9bbd --- /dev/null +++ b/node_modules/webpack/lib/sharing/SharePlugin.js @@ -0,0 +1,92 @@ +/* + 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; diff --git a/node_modules/webpack/lib/sharing/ShareRuntimeModule.js b/node_modules/webpack/lib/sharing/ShareRuntimeModule.js new file mode 100644 index 00000000..a9c66685 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ShareRuntimeModule.js @@ -0,0 +1,151 @@ +/* + 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; diff --git a/node_modules/webpack/lib/sharing/resolveMatchedConfigs.js b/node_modules/webpack/lib/sharing/resolveMatchedConfigs.js new file mode 100644 index 00000000..029e8886 --- /dev/null +++ b/node_modules/webpack/lib/sharing/resolveMatchedConfigs.js @@ -0,0 +1,91 @@ +/* + 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(); + } + resolved.set(/** @type {string} */ (result), config); + resolve(); + } + ); + }); + } 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 }; + }); +}; diff --git a/node_modules/webpack/lib/sharing/utils.js b/node_modules/webpack/lib/sharing/utils.js new file mode 100644 index 00000000..b415df31 --- /dev/null +++ b/node_modules/webpack/lib/sharing/utils.js @@ -0,0 +1,403 @@ +/* + 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 */ + +// 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; + +exports.getRequiredVersionFromDescriptionFile = (data, packageName) => { + if ( + data.optionalDependencies && + typeof data.optionalDependencies === "object" && + packageName in data.optionalDependencies + ) { + return normalizeVersion(data.optionalDependencies[packageName]); + } + if ( + data.dependencies && + typeof data.dependencies === "object" && + packageName in data.dependencies + ) { + return normalizeVersion(data.dependencies[packageName]); + } + if ( + data.peerDependencies && + typeof data.peerDependencies === "object" && + packageName in data.peerDependencies + ) { + return normalizeVersion(data.peerDependencies[packageName]); + } + if ( + data.devDependencies && + typeof data.devDependencies === "object" && + packageName in data.devDependencies + ) { + return normalizeVersion(data.devDependencies[packageName]); + } +}; |
