diff options
Diffstat (limited to 'node_modules/webpack/lib/container')
15 files changed, 1513 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/container/ContainerEntryDependency.js b/node_modules/webpack/lib/container/ContainerEntryDependency.js new file mode 100644 index 00000000..e8aad08b --- /dev/null +++ b/node_modules/webpack/lib/container/ContainerEntryDependency.js @@ -0,0 +1,47 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra, Zackary Jackson @ScriptedAlchemy, Marais Rossouw @maraisr +*/ + +"use strict"; + +const Dependency = require("../Dependency"); +const makeSerializable = require("../util/makeSerializable"); + +/** @typedef {import("./ContainerEntryModule").ExposeOptions} ExposeOptions */ + +class ContainerEntryDependency extends Dependency { + /** + * @param {string} name entry name + * @param {[string, ExposeOptions][]} exposes list of exposed modules + * @param {string} shareScope name of the share scope + */ + constructor(name, exposes, shareScope) { + super(); + this.name = name; + this.exposes = exposes; + this.shareScope = shareScope; + } + + /** + * @returns {string | null} an identifier to merge equal requests + */ + getResourceIdentifier() { + return `container-entry-${this.name}`; + } + + get type() { + return "container entry"; + } + + get category() { + return "esm"; + } +} + +makeSerializable( + ContainerEntryDependency, + "webpack/lib/container/ContainerEntryDependency" +); + +module.exports = ContainerEntryDependency; diff --git a/node_modules/webpack/lib/container/ContainerEntryModule.js b/node_modules/webpack/lib/container/ContainerEntryModule.js new file mode 100644 index 00000000..af805503 --- /dev/null +++ b/node_modules/webpack/lib/container/ContainerEntryModule.js @@ -0,0 +1,293 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra, Zackary Jackson @ScriptedAlchemy, Marais Rossouw @maraisr +*/ + +"use strict"; + +const { OriginalSource, RawSource } = require("webpack-sources"); +const AsyncDependenciesBlock = require("../AsyncDependenciesBlock"); +const Module = require("../Module"); +const { JAVASCRIPT_MODULE_TYPE_DYNAMIC } = require("../ModuleTypeConstants"); +const RuntimeGlobals = require("../RuntimeGlobals"); +const Template = require("../Template"); +const StaticExportsDependency = require("../dependencies/StaticExportsDependency"); +const makeSerializable = require("../util/makeSerializable"); +const ContainerExposedDependency = require("./ContainerExposedDependency"); + +/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */ +/** @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 */ +/** @typedef {import("./ContainerEntryDependency")} ContainerEntryDependency */ + +/** + * @typedef {Object} ExposeOptions + * @property {string[]} import requests to exposed modules (last one is exported) + * @property {string} name custom chunk name for the exposed module + */ + +const SOURCE_TYPES = new Set(["javascript"]); + +class ContainerEntryModule extends Module { + /** + * @param {string} name container entry name + * @param {[string, ExposeOptions][]} exposes list of exposed modules + * @param {string} shareScope name of the share scope + */ + constructor(name, exposes, shareScope) { + super(JAVASCRIPT_MODULE_TYPE_DYNAMIC, null); + this._name = name; + this._exposes = exposes; + this._shareScope = shareScope; + } + + /** + * @returns {Set<string>} types available (do not mutate) + */ + getSourceTypes() { + return SOURCE_TYPES; + } + + /** + * @returns {string} a unique identifier of the module + */ + identifier() { + return `container entry (${this._shareScope}) ${JSON.stringify( + this._exposes + )}`; + } + + /** + * @param {RequestShortener} requestShortener the request shortener + * @returns {string} a user readable identifier of the module + */ + readableIdentifier(requestShortener) { + return `container entry`; + } + + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ + libIdent(options) { + return `${this.layer ? `(${this.layer})/` : ""}webpack/container/entry/${ + 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) { + return callback(null, !this.buildMeta); + } + + /** + * @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, + topLevelDeclarations: new Set(["moduleMap", "get", "init"]) + }; + this.buildMeta.exportsType = "namespace"; + + this.clearDependenciesAndBlocks(); + + for (const [name, options] of this._exposes) { + const block = new AsyncDependenciesBlock( + { + name: options.name + }, + { name }, + options.import[options.import.length - 1] + ); + let idx = 0; + for (const request of options.import) { + const dep = new ContainerExposedDependency(name, request); + dep.loc = { + name, + index: idx++ + }; + + block.addDependency(dep); + } + this.addBlock(block); + } + this.addDependency(new StaticExportsDependency(["get", "init"], false)); + + callback(); + } + + /** + * @param {CodeGenerationContext} context context for code generation + * @returns {CodeGenerationResult} result + */ + codeGeneration({ moduleGraph, chunkGraph, runtimeTemplate }) { + const sources = new Map(); + const runtimeRequirements = new Set([ + RuntimeGlobals.definePropertyGetters, + RuntimeGlobals.hasOwnProperty, + RuntimeGlobals.exports + ]); + const getters = []; + + for (const block of this.blocks) { + const { dependencies } = block; + + const modules = dependencies.map(dependency => { + const dep = /** @type {ContainerExposedDependency} */ (dependency); + return { + name: dep.exposedName, + module: moduleGraph.getModule(dep), + request: dep.userRequest + }; + }); + + let str; + + if (modules.some(m => !m.module)) { + str = runtimeTemplate.throwMissingModuleErrorBlock({ + request: modules.map(m => m.request).join(", ") + }); + } else { + str = `return ${runtimeTemplate.blockPromise({ + block, + message: "", + chunkGraph, + runtimeRequirements + })}.then(${runtimeTemplate.returningFunction( + runtimeTemplate.returningFunction( + `(${modules + .map(({ module, request }) => + runtimeTemplate.moduleRaw({ + module, + chunkGraph, + request, + weak: false, + runtimeRequirements + }) + ) + .join(", ")})` + ) + )});`; + } + + getters.push( + `${JSON.stringify(modules[0].name)}: ${runtimeTemplate.basicFunction( + "", + str + )}` + ); + } + + const source = Template.asString([ + `var moduleMap = {`, + Template.indent(getters.join(",\n")), + "};", + `var get = ${runtimeTemplate.basicFunction("module, getScope", [ + `${RuntimeGlobals.currentRemoteGetScope} = getScope;`, + // reusing the getScope variable to avoid creating a new var (and module is also used later) + "getScope = (", + Template.indent([ + `${RuntimeGlobals.hasOwnProperty}(moduleMap, module)`, + Template.indent([ + "? moduleMap[module]()", + `: Promise.resolve().then(${runtimeTemplate.basicFunction( + "", + "throw new Error('Module \"' + module + '\" does not exist in container.');" + )})` + ]) + ]), + ");", + `${RuntimeGlobals.currentRemoteGetScope} = undefined;`, + "return getScope;" + ])};`, + `var init = ${runtimeTemplate.basicFunction("shareScope, initScope", [ + `if (!${RuntimeGlobals.shareScopeMap}) return;`, + `var name = ${JSON.stringify(this._shareScope)}`, + `var oldScope = ${RuntimeGlobals.shareScopeMap}[name];`, + `if(oldScope && oldScope !== shareScope) throw new Error("Container initialization failed as it has already been initialized with a different share scope");`, + `${RuntimeGlobals.shareScopeMap}[name] = shareScope;`, + `return ${RuntimeGlobals.initializeSharing}(name, initScope);` + ])};`, + "", + "// This exports getters to disallow modifications", + `${RuntimeGlobals.definePropertyGetters}(exports, {`, + Template.indent([ + `get: ${runtimeTemplate.returningFunction("get")},`, + `init: ${runtimeTemplate.returningFunction("init")}` + ]), + "});" + ]); + + sources.set( + "javascript", + this.useSourceMap || this.useSimpleSourceMap + ? new OriginalSource(source, "webpack/container-entry") + : new RawSource(source) + ); + + return { + sources, + runtimeRequirements + }; + } + + /** + * @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 {ObjectSerializerContext} context context + */ + serialize(context) { + const { write } = context; + write(this._name); + write(this._exposes); + write(this._shareScope); + super.serialize(context); + } + + /** + * @param {ObjectDeserializerContext} context context + * @returns {ContainerEntryModule} deserialized container entry module + */ + static deserialize(context) { + const { read } = context; + const obj = new ContainerEntryModule(read(), read(), read()); + obj.deserialize(context); + return obj; + } +} + +makeSerializable( + ContainerEntryModule, + "webpack/lib/container/ContainerEntryModule" +); + +module.exports = ContainerEntryModule; diff --git a/node_modules/webpack/lib/container/ContainerEntryModuleFactory.js b/node_modules/webpack/lib/container/ContainerEntryModuleFactory.js new file mode 100644 index 00000000..4febfebe --- /dev/null +++ b/node_modules/webpack/lib/container/ContainerEntryModuleFactory.js @@ -0,0 +1,27 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra, Zackary Jackson @ScriptedAlchemy, Marais Rossouw @maraisr +*/ + +"use strict"; + +const ModuleFactory = require("../ModuleFactory"); +const ContainerEntryModule = require("./ContainerEntryModule"); + +/** @typedef {import("../ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */ +/** @typedef {import("../ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */ +/** @typedef {import("./ContainerEntryDependency")} ContainerEntryDependency */ + +module.exports = class ContainerEntryModuleFactory extends ModuleFactory { + /** + * @param {ModuleFactoryCreateData} data data object + * @param {function((Error | null)=, ModuleFactoryResult=): void} callback callback + * @returns {void} + */ + create({ dependencies: [dependency] }, callback) { + const dep = /** @type {ContainerEntryDependency} */ (dependency); + callback(null, { + module: new ContainerEntryModule(dep.name, dep.exposes, dep.shareScope) + }); + } +}; diff --git a/node_modules/webpack/lib/container/ContainerExposedDependency.js b/node_modules/webpack/lib/container/ContainerExposedDependency.js new file mode 100644 index 00000000..2cbf04a6 --- /dev/null +++ b/node_modules/webpack/lib/container/ContainerExposedDependency.js @@ -0,0 +1,61 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra, Zackary Jackson @ScriptedAlchemy, Marais Rossouw @maraisr +*/ + +"use strict"; + +const ModuleDependency = require("../dependencies/ModuleDependency"); +const makeSerializable = require("../util/makeSerializable"); + +/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */ +/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */ + +class ContainerExposedDependency extends ModuleDependency { + /** + * @param {string} exposedName public name + * @param {string} request request to module + */ + constructor(exposedName, request) { + super(request); + this.exposedName = exposedName; + } + + get type() { + return "container exposed"; + } + + get category() { + return "esm"; + } + + /** + * @returns {string | null} an identifier to merge equal requests + */ + getResourceIdentifier() { + return `exposed dependency ${this.exposedName}=${this.request}`; + } + + /** + * @param {ObjectSerializerContext} context context + */ + serialize(context) { + context.write(this.exposedName); + super.serialize(context); + } + + /** + * @param {ObjectDeserializerContext} context context + */ + deserialize(context) { + this.exposedName = context.read(); + super.deserialize(context); + } +} + +makeSerializable( + ContainerExposedDependency, + "webpack/lib/container/ContainerExposedDependency" +); + +module.exports = ContainerExposedDependency; diff --git a/node_modules/webpack/lib/container/ContainerPlugin.js b/node_modules/webpack/lib/container/ContainerPlugin.js new file mode 100644 index 00000000..83309104 --- /dev/null +++ b/node_modules/webpack/lib/container/ContainerPlugin.js @@ -0,0 +1,107 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra, Zackary Jackson @ScriptedAlchemy, Marais Rossouw @maraisr +*/ + +"use strict"; + +const createSchemaValidation = require("../util/create-schema-validation"); +const ContainerEntryDependency = require("./ContainerEntryDependency"); +const ContainerEntryModuleFactory = require("./ContainerEntryModuleFactory"); +const ContainerExposedDependency = require("./ContainerExposedDependency"); +const { parseOptions } = require("./options"); + +/** @typedef {import("../../declarations/plugins/container/ContainerPlugin").ContainerPluginOptions} ContainerPluginOptions */ +/** @typedef {import("../Compiler")} Compiler */ + +const validate = createSchemaValidation( + require("../../schemas/plugins/container/ContainerPlugin.check.js"), + () => require("../../schemas/plugins/container/ContainerPlugin.json"), + { + name: "Container Plugin", + baseDataPath: "options" + } +); + +const PLUGIN_NAME = "ContainerPlugin"; + +class ContainerPlugin { + /** + * @param {ContainerPluginOptions} options options + */ + constructor(options) { + validate(options); + + this._options = { + name: options.name, + shareScope: options.shareScope || "default", + library: options.library || { + type: "var", + name: options.name + }, + runtime: options.runtime, + filename: options.filename || undefined, + exposes: parseOptions( + options.exposes, + item => ({ + import: Array.isArray(item) ? item : [item], + name: undefined + }), + item => ({ + import: Array.isArray(item.import) ? item.import : [item.import], + name: item.name || undefined + }) + ) + }; + } + + /** + * Apply the plugin + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + const { name, exposes, shareScope, filename, library, runtime } = + this._options; + + if (!compiler.options.output.enabledLibraryTypes.includes(library.type)) { + compiler.options.output.enabledLibraryTypes.push(library.type); + } + + compiler.hooks.make.tapAsync(PLUGIN_NAME, (compilation, callback) => { + const dep = new ContainerEntryDependency(name, exposes, shareScope); + dep.loc = { name }; + compilation.addEntry( + compilation.options.context, + dep, + { + name, + filename, + runtime, + library + }, + error => { + if (error) return callback(error); + callback(); + } + ); + }); + + compiler.hooks.thisCompilation.tap( + PLUGIN_NAME, + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + ContainerEntryDependency, + new ContainerEntryModuleFactory() + ); + + compilation.dependencyFactories.set( + ContainerExposedDependency, + normalModuleFactory + ); + } + ); + } +} + +module.exports = ContainerPlugin; diff --git a/node_modules/webpack/lib/container/ContainerReferencePlugin.js b/node_modules/webpack/lib/container/ContainerReferencePlugin.js new file mode 100644 index 00000000..f860fbac --- /dev/null +++ b/node_modules/webpack/lib/container/ContainerReferencePlugin.js @@ -0,0 +1,142 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy +*/ + +"use strict"; + +const ExternalsPlugin = require("../ExternalsPlugin"); +const RuntimeGlobals = require("../RuntimeGlobals"); +const createSchemaValidation = require("../util/create-schema-validation"); +const FallbackDependency = require("./FallbackDependency"); +const FallbackItemDependency = require("./FallbackItemDependency"); +const FallbackModuleFactory = require("./FallbackModuleFactory"); +const RemoteModule = require("./RemoteModule"); +const RemoteRuntimeModule = require("./RemoteRuntimeModule"); +const RemoteToExternalDependency = require("./RemoteToExternalDependency"); +const { parseOptions } = require("./options"); + +/** @typedef {import("../../declarations/plugins/container/ContainerReferencePlugin").ContainerReferencePluginOptions} ContainerReferencePluginOptions */ +/** @typedef {import("../../declarations/plugins/container/ContainerReferencePlugin").RemotesConfig} RemotesConfig */ +/** @typedef {import("../Compiler")} Compiler */ + +const validate = createSchemaValidation( + require("../../schemas/plugins/container/ContainerReferencePlugin.check.js"), + () => + require("../../schemas/plugins/container/ContainerReferencePlugin.json"), + { + name: "Container Reference Plugin", + baseDataPath: "options" + } +); + +const slashCode = "/".charCodeAt(0); + +class ContainerReferencePlugin { + /** + * @param {ContainerReferencePluginOptions} options options + */ + constructor(options) { + validate(options); + + this._remoteType = options.remoteType; + this._remotes = parseOptions( + options.remotes, + item => ({ + external: Array.isArray(item) ? item : [item], + shareScope: options.shareScope || "default" + }), + item => ({ + external: Array.isArray(item.external) + ? item.external + : [item.external], + shareScope: item.shareScope || options.shareScope || "default" + }) + ); + } + + /** + * Apply the plugin + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + const { _remotes: remotes, _remoteType: remoteType } = this; + + /** @type {Record<string, string>} */ + const remoteExternals = {}; + for (const [key, config] of remotes) { + let i = 0; + for (const external of config.external) { + if (external.startsWith("internal ")) continue; + remoteExternals[ + `webpack/container/reference/${key}${i ? `/fallback-${i}` : ""}` + ] = external; + i++; + } + } + + new ExternalsPlugin(remoteType, remoteExternals).apply(compiler); + + compiler.hooks.compilation.tap( + "ContainerReferencePlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + RemoteToExternalDependency, + normalModuleFactory + ); + + compilation.dependencyFactories.set( + FallbackItemDependency, + normalModuleFactory + ); + + compilation.dependencyFactories.set( + FallbackDependency, + new FallbackModuleFactory() + ); + + normalModuleFactory.hooks.factorize.tap( + "ContainerReferencePlugin", + data => { + if (!data.request.includes("!")) { + for (const [key, config] of remotes) { + if ( + data.request.startsWith(`${key}`) && + (data.request.length === key.length || + data.request.charCodeAt(key.length) === slashCode) + ) { + return new RemoteModule( + data.request, + config.external.map((external, i) => + external.startsWith("internal ") + ? external.slice(9) + : `webpack/container/reference/${key}${ + i ? `/fallback-${i}` : "" + }` + ), + `.${data.request.slice(key.length)}`, + config.shareScope + ); + } + } + } + } + ); + + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.ensureChunkHandlers) + .tap("ContainerReferencePlugin", (chunk, set) => { + set.add(RuntimeGlobals.module); + set.add(RuntimeGlobals.moduleFactoriesAddOnly); + set.add(RuntimeGlobals.hasOwnProperty); + set.add(RuntimeGlobals.initializeSharing); + set.add(RuntimeGlobals.shareScopeMap); + compilation.addRuntimeModule(chunk, new RemoteRuntimeModule()); + }); + } + ); + } +} + +module.exports = ContainerReferencePlugin; diff --git a/node_modules/webpack/lib/container/FallbackDependency.js b/node_modules/webpack/lib/container/FallbackDependency.js new file mode 100644 index 00000000..088720f5 --- /dev/null +++ b/node_modules/webpack/lib/container/FallbackDependency.js @@ -0,0 +1,64 @@ +/* + 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 FallbackDependency extends Dependency { + /** + * @param {string[]} requests requests + */ + constructor(requests) { + super(); + this.requests = requests; + } + + /** + * @returns {string | null} an identifier to merge equal requests + */ + getResourceIdentifier() { + return `fallback ${this.requests.join(" ")}`; + } + + get type() { + return "fallback"; + } + + get category() { + return "esm"; + } + + /** + * @param {ObjectSerializerContext} context context + */ + serialize(context) { + const { write } = context; + write(this.requests); + super.serialize(context); + } + + /** + * @param {ObjectDeserializerContext} context context + * @returns {FallbackDependency} deserialize fallback dependency + */ + static deserialize(context) { + const { read } = context; + const obj = new FallbackDependency(read()); + obj.deserialize(context); + return obj; + } +} + +makeSerializable( + FallbackDependency, + "webpack/lib/container/FallbackDependency" +); + +module.exports = FallbackDependency; diff --git a/node_modules/webpack/lib/container/FallbackItemDependency.js b/node_modules/webpack/lib/container/FallbackItemDependency.js new file mode 100644 index 00000000..f09f8cf8 --- /dev/null +++ b/node_modules/webpack/lib/container/FallbackItemDependency.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 FallbackItemDependency extends ModuleDependency { + /** + * @param {string} request request + */ + constructor(request) { + super(request); + } + + get type() { + return "fallback item"; + } + + get category() { + return "esm"; + } +} + +makeSerializable( + FallbackItemDependency, + "webpack/lib/container/FallbackItemDependency" +); + +module.exports = FallbackItemDependency; diff --git a/node_modules/webpack/lib/container/FallbackModule.js b/node_modules/webpack/lib/container/FallbackModule.js new file mode 100644 index 00000000..b2ed81b0 --- /dev/null +++ b/node_modules/webpack/lib/container/FallbackModule.js @@ -0,0 +1,183 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy +*/ + +"use strict"; + +const { RawSource } = require("webpack-sources"); +const Module = require("../Module"); +const { WEBPACK_MODULE_TYPE_FALLBACK } = require("../ModuleTypeConstants"); +const RuntimeGlobals = require("../RuntimeGlobals"); +const Template = require("../Template"); +const makeSerializable = require("../util/makeSerializable"); +const FallbackItemDependency = require("./FallbackItemDependency"); + +/** @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(["javascript"]); +const RUNTIME_REQUIREMENTS = new Set([RuntimeGlobals.module]); + +class FallbackModule extends Module { + /** + * @param {string[]} requests list of requests to choose one + */ + constructor(requests) { + super(WEBPACK_MODULE_TYPE_FALLBACK); + this.requests = requests; + this._identifier = `fallback ${this.requests.join(" ")}`; + } + + /** + * @returns {string} a unique identifier of the module + */ + identifier() { + return this._identifier; + } + + /** + * @param {RequestShortener} requestShortener the request shortener + * @returns {string} a user readable identifier of the module + */ + readableIdentifier(requestShortener) { + return this._identifier; + } + + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ + libIdent(options) { + return `${this.layer ? `(${this.layer})/` : ""}webpack/container/fallback/${ + this.requests[0] + }/and ${this.requests.length - 1} more`; + } + + /** + * @param {Chunk} chunk the chunk which condition should be checked + * @param {Compilation} compilation the compilation + * @returns {boolean} true, if the chunk is ok for the module + */ + chunkCondition(chunk, { chunkGraph }) { + return chunkGraph.getNumberOfEntryModules(chunk) > 0; + } + + /** + * @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(); + for (const request of this.requests) + this.addDependency(new FallbackItemDependency(request)); + + 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 this.requests.length * 5 + 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 ids = this.dependencies.map(dep => + chunkGraph.getModuleId(moduleGraph.getModule(dep)) + ); + const code = Template.asString([ + `var ids = ${JSON.stringify(ids)};`, + "var error, result, i = 0;", + `var loop = ${runtimeTemplate.basicFunction("next", [ + "while(i < ids.length) {", + Template.indent([ + `try { next = ${RuntimeGlobals.require}(ids[i++]); } catch(e) { return handleError(e); }`, + "if(next) return next.then ? next.then(handleResult, handleError) : handleResult(next);" + ]), + "}", + "if(error) throw error;" + ])}`, + `var handleResult = ${runtimeTemplate.basicFunction("result", [ + "if(result) return result;", + "return loop();" + ])};`, + `var handleError = ${runtimeTemplate.basicFunction("e", [ + "error = e;", + "return loop();" + ])};`, + "module.exports = loop();" + ]); + const sources = new Map(); + sources.set("javascript", new RawSource(code)); + return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS }; + } + + /** + * @param {ObjectSerializerContext} context context + */ + serialize(context) { + const { write } = context; + write(this.requests); + super.serialize(context); + } + + /** + * @param {ObjectDeserializerContext} context context + * @returns {FallbackModule} deserialized fallback module + */ + static deserialize(context) { + const { read } = context; + const obj = new FallbackModule(read()); + obj.deserialize(context); + return obj; + } +} + +makeSerializable(FallbackModule, "webpack/lib/container/FallbackModule"); + +module.exports = FallbackModule; diff --git a/node_modules/webpack/lib/container/FallbackModuleFactory.js b/node_modules/webpack/lib/container/FallbackModuleFactory.js new file mode 100644 index 00000000..6a9eaeca --- /dev/null +++ b/node_modules/webpack/lib/container/FallbackModuleFactory.js @@ -0,0 +1,27 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra, Zackary Jackson @ScriptedAlchemy, Marais Rossouw @maraisr +*/ + +"use strict"; + +const ModuleFactory = require("../ModuleFactory"); +const FallbackModule = require("./FallbackModule"); + +/** @typedef {import("../ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */ +/** @typedef {import("../ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */ +/** @typedef {import("./FallbackDependency")} FallbackDependency */ + +module.exports = class FallbackModuleFactory extends ModuleFactory { + /** + * @param {ModuleFactoryCreateData} data data object + * @param {function((Error | null)=, ModuleFactoryResult=): void} callback callback + * @returns {void} + */ + create({ dependencies: [dependency] }, callback) { + const dep = /** @type {FallbackDependency} */ (dependency); + callback(null, { + module: new FallbackModule(dep.requests) + }); + } +}; diff --git a/node_modules/webpack/lib/container/ModuleFederationPlugin.js b/node_modules/webpack/lib/container/ModuleFederationPlugin.js new file mode 100644 index 00000000..3652bf58 --- /dev/null +++ b/node_modules/webpack/lib/container/ModuleFederationPlugin.js @@ -0,0 +1,94 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy +*/ + +"use strict"; + +const isValidExternalsType = require("../../schemas/plugins/container/ExternalsType.check.js"); +const SharePlugin = require("../sharing/SharePlugin"); +const createSchemaValidation = require("../util/create-schema-validation"); +const ContainerPlugin = require("./ContainerPlugin"); +const ContainerReferencePlugin = require("./ContainerReferencePlugin"); + +/** @typedef {import("../../declarations/plugins/container/ModuleFederationPlugin").ExternalsType} ExternalsType */ +/** @typedef {import("../../declarations/plugins/container/ModuleFederationPlugin").ModuleFederationPluginOptions} ModuleFederationPluginOptions */ +/** @typedef {import("../../declarations/plugins/container/ModuleFederationPlugin").Shared} Shared */ +/** @typedef {import("../Compiler")} Compiler */ + +const validate = createSchemaValidation( + require("../../schemas/plugins/container/ModuleFederationPlugin.check.js"), + () => require("../../schemas/plugins/container/ModuleFederationPlugin.json"), + { + name: "Module Federation Plugin", + baseDataPath: "options" + } +); +class ModuleFederationPlugin { + /** + * @param {ModuleFederationPluginOptions} options options + */ + constructor(options) { + validate(options); + + this._options = options; + } + + /** + * Apply the plugin + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + const { _options: options } = this; + const library = options.library || { type: "var", name: options.name }; + const remoteType = + options.remoteType || + (options.library && isValidExternalsType(options.library.type) + ? /** @type {ExternalsType} */ (options.library.type) + : "script"); + if ( + library && + !compiler.options.output.enabledLibraryTypes.includes(library.type) + ) { + compiler.options.output.enabledLibraryTypes.push(library.type); + } + compiler.hooks.afterPlugins.tap("ModuleFederationPlugin", () => { + if ( + options.exposes && + (Array.isArray(options.exposes) + ? options.exposes.length > 0 + : Object.keys(options.exposes).length > 0) + ) { + new ContainerPlugin({ + name: options.name, + library, + filename: options.filename, + runtime: options.runtime, + shareScope: options.shareScope, + exposes: options.exposes + }).apply(compiler); + } + if ( + options.remotes && + (Array.isArray(options.remotes) + ? options.remotes.length > 0 + : Object.keys(options.remotes).length > 0) + ) { + new ContainerReferencePlugin({ + remoteType, + shareScope: options.shareScope, + remotes: options.remotes + }).apply(compiler); + } + if (options.shared) { + new SharePlugin({ + shared: options.shared, + shareScope: options.shareScope + }).apply(compiler); + } + }); + } +} + +module.exports = ModuleFederationPlugin; diff --git a/node_modules/webpack/lib/container/RemoteModule.js b/node_modules/webpack/lib/container/RemoteModule.js new file mode 100644 index 00000000..ade329b9 --- /dev/null +++ b/node_modules/webpack/lib/container/RemoteModule.js @@ -0,0 +1,181 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy +*/ + +"use strict"; + +const { RawSource } = require("webpack-sources"); +const Module = require("../Module"); +const { WEBPACK_MODULE_TYPE_REMOTE } = require("../ModuleTypeConstants"); +const RuntimeGlobals = require("../RuntimeGlobals"); +const makeSerializable = require("../util/makeSerializable"); +const FallbackDependency = require("./FallbackDependency"); +const RemoteToExternalDependency = require("./RemoteToExternalDependency"); + +/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */ +/** @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(["remote", "share-init"]); +const RUNTIME_REQUIREMENTS = new Set([RuntimeGlobals.module]); + +class RemoteModule extends Module { + /** + * @param {string} request request string + * @param {string[]} externalRequests list of external requests to containers + * @param {string} internalRequest name of exposed module in container + * @param {string} shareScope the used share scope name + */ + constructor(request, externalRequests, internalRequest, shareScope) { + super(WEBPACK_MODULE_TYPE_REMOTE); + this.request = request; + this.externalRequests = externalRequests; + this.internalRequest = internalRequest; + this.shareScope = shareScope; + this._identifier = `remote (${shareScope}) ${this.externalRequests.join( + " " + )} ${this.internalRequest}`; + } + + /** + * @returns {string} a unique identifier of the module + */ + identifier() { + return this._identifier; + } + + /** + * @param {RequestShortener} requestShortener the request shortener + * @returns {string} a user readable identifier of the module + */ + readableIdentifier(requestShortener) { + return `remote ${this.request}`; + } + + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ + libIdent(options) { + return `${this.layer ? `(${this.layer})/` : ""}webpack/container/remote/${ + this.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 = { + strict: true + }; + + this.clearDependenciesAndBlocks(); + if (this.externalRequests.length === 1) { + this.addDependency( + new RemoteToExternalDependency(this.externalRequests[0]) + ); + } else { + this.addDependency(new FallbackDependency(this.externalRequests)); + } + + 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 6; + } + + /** + * @returns {Set<string>} types available (do not mutate) + */ + getSourceTypes() { + return TYPES; + } + + /** + * @returns {string | null} absolute path which should be used for condition matching (usually the resource path) + */ + nameForCondition() { + return this.request; + } + + /** + * @param {CodeGenerationContext} context context for code generation + * @returns {CodeGenerationResult} result + */ + codeGeneration({ runtimeTemplate, moduleGraph, chunkGraph }) { + const module = moduleGraph.getModule(this.dependencies[0]); + const id = module && chunkGraph.getModuleId(module); + const sources = new Map(); + sources.set("remote", new RawSource("")); + const data = new Map(); + data.set("share-init", [ + { + shareScope: this.shareScope, + initStage: 20, + init: id === undefined ? "" : `initExternal(${JSON.stringify(id)});` + } + ]); + return { sources, data, runtimeRequirements: RUNTIME_REQUIREMENTS }; + } + + /** + * @param {ObjectSerializerContext} context context + */ + serialize(context) { + const { write } = context; + write(this.request); + write(this.externalRequests); + write(this.internalRequest); + write(this.shareScope); + super.serialize(context); + } + + /** + * @param {ObjectDeserializerContext} context context + * @returns {RemoteModule} deserialized module + */ + static deserialize(context) { + const { read } = context; + const obj = new RemoteModule(read(), read(), read(), read()); + obj.deserialize(context); + return obj; + } +} + +makeSerializable(RemoteModule, "webpack/lib/container/RemoteModule"); + +module.exports = RemoteModule; diff --git a/node_modules/webpack/lib/container/RemoteRuntimeModule.js b/node_modules/webpack/lib/container/RemoteRuntimeModule.js new file mode 100644 index 00000000..6d247f1e --- /dev/null +++ b/node_modules/webpack/lib/container/RemoteRuntimeModule.js @@ -0,0 +1,130 @@ +/* + 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"); + +/** @typedef {import("../Chunk")} Chunk */ +/** @typedef {import("./RemoteModule")} RemoteModule */ + +class RemoteRuntimeModule extends RuntimeModule { + constructor() { + super("remotes loading"); + } + + /** + * @returns {string | null} runtime code + */ + generate() { + const { compilation, chunkGraph } = this; + const { runtimeTemplate, moduleGraph } = compilation; + const chunkToRemotesMapping = {}; + const idToExternalAndNameMapping = {}; + for (const chunk of this.chunk.getAllAsyncChunks()) { + const modules = chunkGraph.getChunkModulesIterableBySourceType( + chunk, + "remote" + ); + if (!modules) continue; + const remotes = (chunkToRemotesMapping[chunk.id] = []); + for (const m of modules) { + const module = /** @type {RemoteModule} */ (m); + const name = module.internalRequest; + const id = chunkGraph.getModuleId(module); + const shareScope = module.shareScope; + const dep = module.dependencies[0]; + const externalModule = moduleGraph.getModule(dep); + const externalModuleId = + externalModule && chunkGraph.getModuleId(externalModule); + remotes.push(id); + idToExternalAndNameMapping[id] = [shareScope, name, externalModuleId]; + } + } + return Template.asString([ + `var chunkMapping = ${JSON.stringify( + chunkToRemotesMapping, + null, + "\t" + )};`, + `var idToExternalAndNameMapping = ${JSON.stringify( + idToExternalAndNameMapping, + null, + "\t" + )};`, + `${ + RuntimeGlobals.ensureChunkHandlers + }.remotes = ${runtimeTemplate.basicFunction("chunkId, promises", [ + `if(${RuntimeGlobals.hasOwnProperty}(chunkMapping, chunkId)) {`, + Template.indent([ + `chunkMapping[chunkId].forEach(${runtimeTemplate.basicFunction("id", [ + `var getScope = ${RuntimeGlobals.currentRemoteGetScope};`, + "if(!getScope) getScope = [];", + "var data = idToExternalAndNameMapping[id];", + "if(getScope.indexOf(data) >= 0) return;", + "getScope.push(data);", + `if(data.p) return promises.push(data.p);`, + `var onError = ${runtimeTemplate.basicFunction("error", [ + 'if(!error) error = new Error("Container missing");', + 'if(typeof error.message === "string")', + Template.indent( + `error.message += '\\nwhile loading "' + data[1] + '" from ' + data[2];` + ), + `${ + RuntimeGlobals.moduleFactories + }[id] = ${runtimeTemplate.basicFunction("", ["throw error;"])}`, + "data.p = 0;" + ])};`, + `var handleFunction = ${runtimeTemplate.basicFunction( + "fn, arg1, arg2, d, next, first", + [ + "try {", + Template.indent([ + "var promise = fn(arg1, arg2);", + "if(promise && promise.then) {", + Template.indent([ + `var p = promise.then(${runtimeTemplate.returningFunction( + "next(result, d)", + "result" + )}, onError);`, + `if(first) promises.push(data.p = p); else return p;` + ]), + "} else {", + Template.indent(["return next(promise, d, first);"]), + "}" + ]), + "} catch(error) {", + Template.indent(["onError(error);"]), + "}" + ] + )}`, + `var onExternal = ${runtimeTemplate.returningFunction( + `external ? handleFunction(${RuntimeGlobals.initializeSharing}, data[0], 0, external, onInitialized, first) : onError()`, + "external, _, first" + )};`, + `var onInitialized = ${runtimeTemplate.returningFunction( + `handleFunction(external.get, data[1], getScope, 0, onFactory, first)`, + "_, external, first" + )};`, + `var onFactory = ${runtimeTemplate.basicFunction("factory", [ + "data.p = 1;", + `${ + RuntimeGlobals.moduleFactories + }[id] = ${runtimeTemplate.basicFunction("module", [ + "module.exports = factory();" + ])}` + ])};`, + `handleFunction(${RuntimeGlobals.require}, data[2], 0, 0, onExternal, 1);` + ])});` + ]), + "}" + ])}` + ]); + } +} + +module.exports = RemoteRuntimeModule; diff --git a/node_modules/webpack/lib/container/RemoteToExternalDependency.js b/node_modules/webpack/lib/container/RemoteToExternalDependency.js new file mode 100644 index 00000000..df7fd1f8 --- /dev/null +++ b/node_modules/webpack/lib/container/RemoteToExternalDependency.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 RemoteToExternalDependency extends ModuleDependency { + /** + * @param {string} request request + */ + constructor(request) { + super(request); + } + + get type() { + return "remote to external"; + } + + get category() { + return "esm"; + } +} + +makeSerializable( + RemoteToExternalDependency, + "webpack/lib/container/RemoteToExternalDependency" +); + +module.exports = RemoteToExternalDependency; diff --git a/node_modules/webpack/lib/container/options.js b/node_modules/webpack/lib/container/options.js new file mode 100644 index 00000000..8cd9698a --- /dev/null +++ b/node_modules/webpack/lib/container/options.js @@ -0,0 +1,91 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +/** @template T @typedef {(string | Record<string, string | string[] | T>)[] | Record<string, string | string[] | T>} ContainerOptionsFormat */ + +/** + * @template T + * @template N + * @param {ContainerOptionsFormat<T>} options options passed by the user + * @param {function(string | string[], string) : N} normalizeSimple normalize a simple item + * @param {function(T, string) : N} normalizeOptions normalize a complex item + * @param {function(string, N): void} fn processing function + * @returns {void} + */ +const process = (options, normalizeSimple, normalizeOptions, fn) => { + const array = items => { + for (const item of items) { + if (typeof item === "string") { + fn(item, normalizeSimple(item, item)); + } else if (item && typeof item === "object") { + object(item); + } else { + throw new Error("Unexpected options format"); + } + } + }; + const object = obj => { + for (const [key, value] of Object.entries(obj)) { + if (typeof value === "string" || Array.isArray(value)) { + fn(key, normalizeSimple(value, key)); + } else { + fn(key, normalizeOptions(value, key)); + } + } + }; + if (!options) { + return; + } else if (Array.isArray(options)) { + array(options); + } else if (typeof options === "object") { + object(options); + } else { + throw new Error("Unexpected options format"); + } +}; + +/** + * @template T + * @template R + * @param {ContainerOptionsFormat<T>} options options passed by the user + * @param {function(string | string[], string) : R} normalizeSimple normalize a simple item + * @param {function(T, string) : R} normalizeOptions normalize a complex item + * @returns {[string, R][]} parsed options + */ +const parseOptions = (options, normalizeSimple, normalizeOptions) => { + /** @type {[string, R][]} */ + const items = []; + process(options, normalizeSimple, normalizeOptions, (key, value) => { + items.push([key, value]); + }); + return items; +}; + +/** + * @template T + * @param {string} scope scope name + * @param {ContainerOptionsFormat<T>} options options passed by the user + * @returns {Record<string, string | string[] | T>} options to spread or pass + */ +const scope = (scope, options) => { + /** @type {Record<string, string | string[] | T>} */ + const obj = {}; + process( + options, + item => /** @type {string | string[] | T} */ (item), + item => /** @type {string | string[] | T} */ (item), + (key, value) => { + obj[ + key.startsWith("./") ? `${scope}${key.slice(1)}` : `${scope}/${key}` + ] = value; + } + ); + return obj; +}; + +exports.parseOptions = parseOptions; +exports.scope = scope; |
