diff options
Diffstat (limited to 'node_modules/webpack/lib/sharing')
13 files changed, 2326 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..dcf40e7f --- /dev/null +++ b/node_modules/webpack/lib/sharing/ConsumeSharedModule.js @@ -0,0 +1,268 @@ +/* + 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("../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 */ +/** @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 {SourceTypes} 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 + }); + } + } + + const args = [ + JSON.stringify(shareScope), + JSON.stringify(shareKey), + JSON.stringify(eager) + ]; + if (requiredVersion) { + args.push(stringifyHoley(requiredVersion)); + } + if (fallbackCode) { + args.push(fallbackCode); + } + + let fn; + + if (requiredVersion) { + if (strictVersion) { + fn = singleton ? "loadStrictSingletonVersion" : "loadStrictVersion"; + } else { + fn = singleton ? "loadSingletonVersion" : "loadVersion"; + } + } else { + fn = singleton ? "loadSingleton" : "load"; + } + + 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..efc52490 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ConsumeSharedPlugin.js @@ -0,0 +1,356 @@ +/* + 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("../util/semver").SemVerRange} SemVerRange */ +/** @typedef {import("./ConsumeSharedModule").ConsumeOptions} ConsumeOptions */ +/** @typedef {import("./utils").DescriptionFile} DescriptionFile */ + +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} */ + const 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: Boolean(item.singleton), + eager: Boolean(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( + /** + * @param {(value?: string) => void} resolve resolve + */ + resolve => { + if (!config.import) { + resolve(); + return; + } + 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(/** @type {string} */ (result)); + } + ); + } + ), + new Promise( + /** + * @param {(value?: SemVerRange) => void} resolve resolve + */ + resolve => { + if (config.requiredVersion !== undefined) { + resolve(/** @type {SemVerRange} */ (config.requiredVersion)); + return; + } + 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. + resolve(); + return; + } + const match = /^((?:@[^\\/]+[\\/])?[^\\/]+)/.exec(request); + if (!match) { + requiredVersionWarning( + "Unable to extract the package name from request." + ); + resolve(); + return; + } + 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 } = + /** @type {DescriptionFile} */ (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]) => + 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; diff --git a/node_modules/webpack/lib/sharing/ConsumeSharedRuntimeModule.js b/node_modules/webpack/lib/sharing/ConsumeSharedRuntimeModule.js new file mode 100644 index 00000000..7dc3209b --- /dev/null +++ b/node_modules/webpack/lib/sharing/ConsumeSharedRuntimeModule.js @@ -0,0 +1,353 @@ +/* + 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("../ChunkGraph").ModuleId} ModuleId */ +/** @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 = m; + const id = /** @type {ModuleId} */ (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 exists = ${runtimeTemplate.basicFunction("scope, key", [ + `return scope && ${RuntimeGlobals.hasOwnProperty}(scope, key);` + ])}`, + `var get = ${runtimeTemplate.basicFunction("entry", [ + "entry.loaded = 1;", + "return entry.get()" + ])};`, + `var eagerOnly = ${runtimeTemplate.basicFunction("versions", [ + `return Object.keys(versions).reduce(${runtimeTemplate.basicFunction( + "filtered, version", + Template.indent([ + "if (versions[version].eager) {", + Template.indent(["filtered[version] = versions[version];"]), + "}", + "return filtered;" + ]) + )}, {});` + ])};`, + `var findLatestVersion = ${runtimeTemplate.basicFunction( + "scope, key, eager", + [ + "var versions = eager ? eagerOnly(scope[key]) : 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 findSatisfyingVersion = ${runtimeTemplate.basicFunction( + "scope, key, requiredVersion, eager", + [ + "var versions = eager ? eagerOnly(scope[key]) : 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 findSingletonVersionKey = ${runtimeTemplate.basicFunction( + "scope, key, eager", + [ + "var versions = eager ? eagerOnly(scope[key]) : 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 getInvalidVersionMessage = ${runtimeTemplate.basicFunction( + "scope, scopeName, key, requiredVersion, eager", + [ + "var versions = scope[key];", + 'return "No satisfying version (" + rangeToString(requiredVersion) + ")" + (eager ? " for eager consumption" : "") + " 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 fail = ${runtimeTemplate.basicFunction("msg", [ + "throw new Error(msg);" + ])}`, + `var failAsNotExist = ${runtimeTemplate.basicFunction("scopeName, key", [ + 'return fail("Shared module " + key + " doesn\'t exist in shared scope " + scopeName);' + ])}`, + `var warn = /*#__PURE__*/ ${ + compilation.outputOptions.ignoreBrowserWarnings + ? runtimeTemplate.basicFunction("", "") + : runtimeTemplate.basicFunction("msg", [ + 'if (typeof console !== "undefined" && console.warn) console.warn(msg);' + ]) + };`, + `var init = ${runtimeTemplate.returningFunction( + Template.asString([ + "function(scopeName, key, eager, c, d) {", + Template.indent([ + `var promise = ${RuntimeGlobals.initializeSharing}(scopeName);`, + // if we require eager shared, we expect it to be already loaded before it requested, no need to wait the whole scope loaded. + "if (promise && promise.then && !eager) { ", + Template.indent([ + `return promise.then(fn.bind(fn, scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], key, false, c, d));` + ]), + "}", + `return fn(scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], key, eager, c, d);` + ]), + "}" + ]), + "fn" + )};`, + "", + `var useFallback = ${runtimeTemplate.basicFunction( + "scopeName, key, fallback", + ["return fallback ? fallback() : failAsNotExist(scopeName, key);"] + )}`, + `var load = /*#__PURE__*/ init(${runtimeTemplate.basicFunction( + "scopeName, scope, key, eager, fallback", + [ + "if (!exists(scope, key)) return useFallback(scopeName, key, fallback);", + "return get(findLatestVersion(scope, key, eager));" + ] + )});`, + `var loadVersion = /*#__PURE__*/ init(${runtimeTemplate.basicFunction( + "scopeName, scope, key, eager, requiredVersion, fallback", + [ + "if (!exists(scope, key)) return useFallback(scopeName, key, fallback);", + "var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);", + "if (satisfyingVersion) return get(satisfyingVersion);", + "warn(getInvalidVersionMessage(scope, scopeName, key, requiredVersion, eager))", + "return get(findLatestVersion(scope, key, eager));" + ] + )});`, + `var loadStrictVersion = /*#__PURE__*/ init(${runtimeTemplate.basicFunction( + "scopeName, scope, key, eager, requiredVersion, fallback", + [ + "if (!exists(scope, key)) return useFallback(scopeName, key, fallback);", + "var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);", + "if (satisfyingVersion) return get(satisfyingVersion);", + "if (fallback) return fallback();", + "fail(getInvalidVersionMessage(scope, scopeName, key, requiredVersion, eager));" + ] + )});`, + `var loadSingleton = /*#__PURE__*/ init(${runtimeTemplate.basicFunction( + "scopeName, scope, key, eager, fallback", + [ + "if (!exists(scope, key)) return useFallback(scopeName, key, fallback);", + "var version = findSingletonVersionKey(scope, key, eager);", + "return get(scope[key][version]);" + ] + )});`, + `var loadSingletonVersion = /*#__PURE__*/ init(${runtimeTemplate.basicFunction( + "scopeName, scope, key, eager, requiredVersion, fallback", + [ + "if (!exists(scope, key)) return useFallback(scopeName, key, fallback);", + "var version = findSingletonVersionKey(scope, key, eager);", + "if (!satisfy(requiredVersion, version)) {", + Template.indent([ + "warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));" + ]), + "}", + "return get(scope[key][version]);" + ] + )});`, + `var loadStrictSingletonVersion = /*#__PURE__*/ init(${runtimeTemplate.basicFunction( + "scopeName, scope, key, eager, requiredVersion, fallback", + [ + "if (!exists(scope, key)) return useFallback(scopeName, key, fallback);", + "var version = findSingletonVersionKey(scope, key, eager);", + "if (!satisfy(requiredVersion, version)) {", + Template.indent([ + "fail(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));" + ]), + "}", + "return get(scope[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; diff --git a/node_modules/webpack/lib/sharing/ProvideForSharedDependency.js b/node_modules/webpack/lib/sharing/ProvideForSharedDependency.js new file mode 100644 index 00000000..4de679a6 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ProvideForSharedDependency.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 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..22848391 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ProvideSharedModule.js @@ -0,0 +1,195 @@ +/* + 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; 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..c57b7632 --- /dev/null +++ b/node_modules/webpack/lib/sharing/ProvideSharedPlugin.js @@ -0,0 +1,244 @@ +/* + 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: Boolean(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; diff --git a/node_modules/webpack/lib/sharing/SharePlugin.js b/node_modules/webpack/lib/sharing/SharePlugin.js new file mode 100644 index 00000000..65935b30 --- /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..0f63ef68 --- /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..a54a76ab --- /dev/null +++ b/node_modules/webpack/lib/sharing/resolveMatchedConfigs.js @@ -0,0 +1,92 @@ +/* + 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 + */ +module.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( + // eslint-disable-next-line array-callback-return + 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 }; + }); +}; diff --git a/node_modules/webpack/lib/sharing/utils.js b/node_modules/webpack/lib/sharing/utils.js new file mode 100644 index 00000000..29aa4d6e --- /dev/null +++ b/node_modules/webpack/lib/sharing/utils.js @@ -0,0 +1,394 @@ +/* + 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; + } + + commithash = !type ? hash : `#${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 (_err) {} + + 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 (_err) { + return false; + } + + return true; +} + +/** + * get right dep version from git url + * @inner + * @param {string} gitUrl git url + * @returns {string} dep version + */ +function getGitUrlVersion(gitUrl) { + const oriGitUrl = gitUrl; + // github extreme shorthand + gitUrl = RE_URL_GITHUB_EXTREME_SHORT.test(gitUrl) + ? `github:${gitUrl}` + : correctProtocol(gitUrl); + + gitUrl = correctUrl(gitUrl); + + let parsed; + try { + parsed = new URL(gitUrl); + // eslint-disable-next-line no-empty + } catch (_err) {} + + 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); +} + +module.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()); +} + +module.exports.normalizeVersion = normalizeVersion; + +/** @typedef {{ data: JsonObject, path: string }} DescriptionFile */ + +/** + * @param {InputFileSystem} fs file system + * @param {string} directory directory to start looking into + * @param {string[]} descriptionFiles possible description filenames + * @param {function((Error | null)=, DescriptionFile=): 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(); +}; +module.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] + ) + ); + } + } +}; +module.exports.getRequiredVersionFromDescriptionFile = + getRequiredVersionFromDescriptionFile; |
