|
|
/* MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra*/
"use strict";
const { OriginalSource, RawSource } = require("webpack-sources");const ConcatenationScope = require("./ConcatenationScope");const EnvironmentNotSupportAsyncWarning = require("./EnvironmentNotSupportAsyncWarning");const { UsageState } = require("./ExportsInfo");const InitFragment = require("./InitFragment");const Module = require("./Module");const { CSS_IMPORT_TYPES, CSS_URL_TYPES, JS_TYPES} = require("./ModuleSourceTypesConstants");const { JAVASCRIPT_MODULE_TYPE_DYNAMIC } = require("./ModuleTypeConstants");const RuntimeGlobals = require("./RuntimeGlobals");const Template = require("./Template");const { DEFAULTS } = require("./config/defaults");const StaticExportsDependency = require("./dependencies/StaticExportsDependency");const createHash = require("./util/createHash");const extractUrlAndGlobal = require("./util/extractUrlAndGlobal");const makeSerializable = require("./util/makeSerializable");const propertyAccess = require("./util/propertyAccess");const { register } = require("./util/serialization");
/** @typedef {import("webpack-sources").Source} Source *//** @typedef {import("../declarations/WebpackOptions").HashFunction} HashFunction *//** @typedef {import("./config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions *//** @typedef {import("./Chunk")} Chunk *//** @typedef {import("./ChunkGraph")} ChunkGraph *//** @typedef {import("./Compilation")} Compilation *//** @typedef {import("./Compilation").UnsafeCacheData} UnsafeCacheData *//** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext *//** @typedef {import("./ExportsInfo")} ExportsInfo *//** @typedef {import("./Generator").GenerateContext} GenerateContext *//** @typedef {import("./Generator").SourceTypes} SourceTypes *//** @typedef {import("./Module").ModuleId} ModuleId *//** @typedef {import("./Module").BuildCallback} BuildCallback *//** @typedef {import("./Module").BuildInfo} BuildInfo *//** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext *//** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult *//** @typedef {import("./Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext *//** @typedef {import("./Module").LibIdentOptions} LibIdentOptions *//** @typedef {import("./Module").LibIdent} LibIdent *//** @typedef {import("./Module").NeedBuildCallback} NeedBuildCallback *//** @typedef {import("./Module").NeedBuildContext} NeedBuildContext *//** @typedef {import("./Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements *//** @typedef {import("./ModuleGraph")} ModuleGraph *//** @typedef {import("./NormalModuleFactory")} NormalModuleFactory *//** @typedef {import("./RequestShortener")} RequestShortener *//** @typedef {import("./ResolverFactory").ResolverWithOptions} ResolverWithOptions *//** @typedef {import("./RuntimeTemplate")} RuntimeTemplate *//** @typedef {import("./javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext *//** @typedef {import("./javascript/JavascriptParser").ImportAttributes} ImportAttributes *//** @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/runtime").RuntimeSpec} RuntimeSpec */
/** @typedef {{ attributes?: ImportAttributes, externalType: "import" | "module" | undefined }} ImportDependencyMeta *//** @typedef {{ layer?: string, supports?: string, media?: string }} CssImportDependencyMeta *//** @typedef {{ sourceType: "css-url" }} AssetDependencyMeta */
/** @typedef {ImportDependencyMeta | CssImportDependencyMeta | AssetDependencyMeta} DependencyMeta */
/** * @typedef {object} SourceData * @property {boolean=} iife * @property {string=} init * @property {string} expression * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments * @property {ReadOnlyRuntimeRequirements=} runtimeRequirements * @property {[string, string][]=} specifiers */
/** @typedef {true | [string, string][]} Imported */
const RUNTIME_REQUIREMENTS = new Set([RuntimeGlobals.module]);const RUNTIME_REQUIREMENTS_FOR_SCRIPT = new Set([RuntimeGlobals.loadScript]);const RUNTIME_REQUIREMENTS_FOR_MODULE = new Set([ RuntimeGlobals.definePropertyGetters]);const EMPTY_RUNTIME_REQUIREMENTS = new Set([]);
/** * @param {string | string[]} variableName the variable name or path * @param {string} type the module system * @returns {SourceData} the generated source */const getSourceForGlobalVariableExternal = (variableName, type) => { if (!Array.isArray(variableName)) { // make it an array as the look up works the same basically
variableName = [variableName]; }
// needed for e.g. window["some"]["thing"]
const objectLookup = variableName .map((r) => `[${JSON.stringify(r)}]`) .join(""); return { iife: type === "this", expression: `${type}${objectLookup}` };};
/** @typedef {string | string[]} ModuleAndSpecifiers */
/** * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request * @returns {SourceData} the generated source */const getSourceForCommonJsExternal = (moduleAndSpecifiers) => { if (!Array.isArray(moduleAndSpecifiers)) { return { expression: `require(${JSON.stringify(moduleAndSpecifiers)})` }; } const moduleName = moduleAndSpecifiers[0]; return { expression: `require(${JSON.stringify(moduleName)})${propertyAccess( moduleAndSpecifiers, 1 )}`
};};
/** * @param {RuntimeTemplate} runtimeTemplate the runtime template * @returns {InitFragment<ChunkRenderContext>} code */const getExternalModuleNodeCommonjsInitFragment = (runtimeTemplate) => { const importMetaName = runtimeTemplate.outputOptions.importMetaName;
return new InitFragment( `import { createRequire as __WEBPACK_EXTERNAL_createRequire } from ${runtimeTemplate.renderNodePrefixForCoreModule( "module" )};\n${runtimeTemplate.renderConst()} __WEBPACK_EXTERNAL_createRequire_require = __WEBPACK_EXTERNAL_createRequire(${importMetaName}.url);\n`,
InitFragment.STAGE_HARMONY_IMPORTS, 0, "external module node-commonjs" );};
/** * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request * @param {RuntimeTemplate} runtimeTemplate the runtime template * @returns {SourceData} the generated source */const getSourceForCommonJsExternalInNodeModule = ( moduleAndSpecifiers, runtimeTemplate) => { const chunkInitFragments = [ getExternalModuleNodeCommonjsInitFragment(runtimeTemplate) ]; if (!Array.isArray(moduleAndSpecifiers)) { return { chunkInitFragments, expression: `__WEBPACK_EXTERNAL_createRequire_require(${JSON.stringify( moduleAndSpecifiers )})`
}; } const moduleName = moduleAndSpecifiers[0]; return { chunkInitFragments, expression: `__WEBPACK_EXTERNAL_createRequire_require(${JSON.stringify( moduleName )})${propertyAccess(moduleAndSpecifiers, 1)}`
};};
/** * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request * @param {RuntimeTemplate} runtimeTemplate the runtime template * @param {ImportDependencyMeta=} dependencyMeta the dependency meta * @returns {SourceData} the generated source */const getSourceForImportExternal = ( moduleAndSpecifiers, runtimeTemplate, dependencyMeta) => { const importName = runtimeTemplate.outputOptions.importFunctionName; if ( !runtimeTemplate.supportsDynamicImport() && (importName === "import" || importName === "module-import") ) { throw new Error( "The target environment doesn't support 'import()' so it's not possible to use external type 'import'" ); } const attributes = dependencyMeta && dependencyMeta.attributes ? dependencyMeta.attributes._isLegacyAssert ? `, { assert: ${JSON.stringify( dependencyMeta.attributes, importAssertionReplacer )} }`
: `, { with: ${JSON.stringify(dependencyMeta.attributes)} }` : ""; if (!Array.isArray(moduleAndSpecifiers)) { return { expression: `${importName}(${JSON.stringify( moduleAndSpecifiers )}${attributes});`
}; } if (moduleAndSpecifiers.length === 1) { return { expression: `${importName}(${JSON.stringify( moduleAndSpecifiers[0] )}${attributes});`
}; } const moduleName = moduleAndSpecifiers[0]; return { expression: `${importName}(${JSON.stringify( moduleName )}${attributes}).then(${runtimeTemplate.returningFunction( `module${propertyAccess(moduleAndSpecifiers, 1)}`, "module" )});`
};};
/** * @param {string} key key * @param {ImportAttributes | string | boolean | undefined} value value * @returns {ImportAttributes | string | boolean | undefined} replaced value */const importAssertionReplacer = (key, value) => { if (key === "_isLegacyAssert") { return; }
return value;};
/** * @extends {InitFragment<GenerateContext>} */class ModuleExternalInitFragment extends InitFragment { /** * @param {string} request import source * @param {Imported} imported the imported specifiers * @param {string=} ident recomputed ident * @param {ImportDependencyMeta=} dependencyMeta the dependency meta * @param {HashFunction=} hashFunction the hash function to use */ constructor( request, imported, ident, dependencyMeta, hashFunction = DEFAULTS.HASH_FUNCTION ) { if (ident === undefined) { ident = Template.toIdentifier(request); if (ident !== request) { ident += `_${createHash(hashFunction) .update(request) .digest("hex") .slice(0, 8)}`;
} }
super( "", InitFragment.STAGE_HARMONY_IMPORTS, 0, `external module import ${ident} ${imported === true ? imported : imported.join(" ")}` ); this._ident = ident; this._request = request; this._dependencyMeta = dependencyMeta; this._identifier = this.buildIdentifier(ident); this._imported = this.buildImported(imported); }
/** * @returns {Imported} imported */ getImported() { return this._imported; }
/** * @param {Imported} imported imported */ setImported(imported) { this._imported = imported; }
/** * @param {GenerateContext} context context * @returns {string | Source | undefined} the source code that will be included as initialization code */ getContent(context) { const { _dependencyMeta: dependencyMeta, _imported: imported, _request: request, _identifier: identifier } = this; const attributes = dependencyMeta && dependencyMeta.attributes ? dependencyMeta.attributes._isLegacyAssert && dependencyMeta.attributes._isLegacyAssert ? ` assert ${JSON.stringify( dependencyMeta.attributes, importAssertionReplacer )}`
: ` with ${JSON.stringify(dependencyMeta.attributes)}` : ""; let content = ""; if (imported === true) { // namespace
content = `import * as ${identifier} from ${JSON.stringify(request)}${ attributes };\n`;
} else if (imported.length === 0) { // just import, no use
content = `import ${JSON.stringify(request)}${attributes};\n`; } else { content = `import { ${imported .map(([name, finalName]) => { if (name !== finalName) { return `${name} as ${finalName}`; } return name; }) .join(", ")} } from ${JSON.stringify(request)}${attributes};\n`;
} return content; }
getNamespaceIdentifier() { return this._identifier; }
/** * @param {string} ident ident * @returns {string} identifier */ buildIdentifier(ident) { return `__WEBPACK_EXTERNAL_MODULE_${ident}__`; }
/** * @param {Imported} imported imported * @returns {Imported} normalized imported */ buildImported(imported) { if (Array.isArray(imported)) { return imported.map(([name]) => { const ident = `${this._ident}_${name}`; return [name, this.buildIdentifier(ident)]; }); } return imported; }}
register( ModuleExternalInitFragment, "webpack/lib/ExternalModule", "ModuleExternalInitFragment", { serialize(obj, { write }) { write(obj._request); write(obj._imported); write(obj._ident); write(obj._dependencyMeta); }, deserialize({ read }) { return new ModuleExternalInitFragment(read(), read(), read(), read()); } });
/** * @param {string} input input * @param {ExportsInfo} exportsInfo the exports info * @param {RuntimeSpec=} runtime the runtime * @param {RuntimeTemplate=} runtimeTemplate the runtime template * @returns {string | undefined} the module remapping */const generateModuleRemapping = ( input, exportsInfo, runtime, runtimeTemplate) => { if (exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused) { const properties = []; for (const exportInfo of exportsInfo.orderedExports) { const used = exportInfo.getUsedName(exportInfo.name, runtime); if (!used) continue; const nestedInfo = exportInfo.getNestedExportsInfo(); if (nestedInfo) { const nestedExpr = generateModuleRemapping( `${input}${propertyAccess([exportInfo.name])}`, nestedInfo ); if (nestedExpr) { properties.push(`[${JSON.stringify(used)}]: y(${nestedExpr})`); continue; } } properties.push( `[${JSON.stringify(used)}]: ${ /** @type {RuntimeTemplate} */ (runtimeTemplate).returningFunction( `${input}${propertyAccess([exportInfo.name])}` ) }`
); } return `x({ ${properties.join(", ")} })`; }};
/** * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request * @param {ExportsInfo} exportsInfo exports info of this module * @param {RuntimeSpec} runtime the runtime * @param {RuntimeTemplate} runtimeTemplate the runtime template * @param {ImportDependencyMeta} dependencyMeta the dependency meta * @param {ConcatenationScope=} concatenationScope concatenationScope * @returns {SourceData} the generated source */const getSourceForModuleExternal = ( moduleAndSpecifiers, exportsInfo, runtime, runtimeTemplate, dependencyMeta, concatenationScope) => { if (!Array.isArray(moduleAndSpecifiers)) { moduleAndSpecifiers = [moduleAndSpecifiers]; }
/** @type {Imported} */ let imported = true; if (concatenationScope) { const usedExports = exportsInfo.getUsedExports(runtime); switch (usedExports) { case true: case null: // unknown exports
imported = true; break; case false: // no used exports
imported = []; break; default: imported = [...usedExports.entries()]; } }
const initFragment = new ModuleExternalInitFragment( moduleAndSpecifiers[0], imported, undefined, dependencyMeta, runtimeTemplate.outputOptions.hashFunction ); const normalizedImported = initFragment.getImported(); const specifiers = normalizedImported === true ? undefined : /** @type {[string, string][]} */ ( normalizedImported.map(([name, rawFinalName]) => { let finalName = rawFinalName; let counter = 0;
if (concatenationScope) { while (!concatenationScope.registerUsedName(finalName)) { finalName = `${finalName}_${counter++}`; } } return [name, finalName]; }) );
const baseAccess = `${initFragment.getNamespaceIdentifier()}${propertyAccess( moduleAndSpecifiers, 1 )}`;
let expression = baseAccess;
const useNamespace = imported === true; let moduleRemapping; if (useNamespace) { moduleRemapping = generateModuleRemapping( baseAccess, exportsInfo, runtime, runtimeTemplate ); expression = moduleRemapping || baseAccess; } return { expression, init: moduleRemapping ? `var x = ${runtimeTemplate.basicFunction( "y", `var x = {}; ${RuntimeGlobals.definePropertyGetters}(x, y); return x` )} \nvar y = ${runtimeTemplate.returningFunction( runtimeTemplate.returningFunction("x"), "x" )}`
: undefined, specifiers, runtimeRequirements: moduleRemapping ? RUNTIME_REQUIREMENTS_FOR_MODULE : undefined, chunkInitFragments: [ /** @type {InitFragment<EXPECTED_ANY>} */ (initFragment) ] };};
/** * @param {string | string[]} urlAndGlobal the script request * @param {RuntimeTemplate} runtimeTemplate the runtime template * @returns {SourceData} the generated source */const getSourceForScriptExternal = (urlAndGlobal, runtimeTemplate) => { if (typeof urlAndGlobal === "string") { urlAndGlobal = extractUrlAndGlobal(urlAndGlobal); } const url = urlAndGlobal[0]; const globalName = urlAndGlobal[1]; return { init: "var __webpack_error__ = new Error();", expression: `new Promise(${runtimeTemplate.basicFunction( "resolve, reject", [ `if(typeof ${globalName} !== "undefined") return resolve();`, `${RuntimeGlobals.loadScript}(${JSON.stringify( url )}, ${runtimeTemplate.basicFunction("event", [ `if(typeof ${globalName} !== "undefined") return resolve();`, "var errorType = event && (event.type === 'load' ? 'missing' : event.type);", "var realSrc = event && event.target && event.target.src;", "__webpack_error__.message = 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';", "__webpack_error__.name = 'ScriptExternalLoadError';", "__webpack_error__.type = errorType;", "__webpack_error__.request = realSrc;", "reject(__webpack_error__);" ])}, ${JSON.stringify(globalName)});`
] )}).then(${runtimeTemplate.returningFunction( `${globalName}${propertyAccess(urlAndGlobal, 2)}` )})`,
runtimeRequirements: RUNTIME_REQUIREMENTS_FOR_SCRIPT };};
/** * @param {string} variableName the variable name to check * @param {string} request the request path * @param {RuntimeTemplate} runtimeTemplate the runtime template * @returns {string} the generated source */const checkExternalVariable = (variableName, request, runtimeTemplate) => `if(typeof ${variableName} === 'undefined') { ${runtimeTemplate.throwMissingModuleErrorBlock( { request } )} }\n`;
/** * @param {ModuleId | string} id the module id * @param {boolean} optional true, if the module is optional * @param {string | string[]} request the request path * @param {RuntimeTemplate} runtimeTemplate the runtime template * @returns {SourceData} the generated source */const getSourceForAmdOrUmdExternal = ( id, optional, request, runtimeTemplate) => { const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier( `${id}` )}__`;
return { init: optional ? checkExternalVariable( externalVariable, Array.isArray(request) ? request.join(".") : request, runtimeTemplate ) : undefined, expression: externalVariable };};
/** * @param {boolean} optional true, if the module is optional * @param {string | string[]} request the request path * @param {RuntimeTemplate} runtimeTemplate the runtime template * @returns {SourceData} the generated source */const getSourceForDefaultCase = (optional, request, runtimeTemplate) => { if (!Array.isArray(request)) { // make it an array as the look up works the same basically
request = [request]; }
const variableName = request[0]; const objectLookup = propertyAccess(request, 1); return { init: optional ? checkExternalVariable(variableName, request.join("."), runtimeTemplate) : undefined, expression: `${variableName}${objectLookup}` };};
/** @typedef {Record<string, string | string[]>} RequestRecord *//** @typedef {string | string[] | RequestRecord} ExternalModuleRequest */
class ExternalModule extends Module { /** * @param {ExternalModuleRequest} request request * @param {string} type type * @param {string} userRequest user request * @param {DependencyMeta=} dependencyMeta dependency meta */ constructor(request, type, userRequest, dependencyMeta) { super(JAVASCRIPT_MODULE_TYPE_DYNAMIC, null);
// Info from Factory
/** @type {ExternalModuleRequest} */ this.request = request; /** @type {string} */ this.externalType = type; /** @type {string} */ this.userRequest = userRequest; /** @type {DependencyMeta=} */ this.dependencyMeta = dependencyMeta; }
/** * @returns {SourceTypes} types available (do not mutate) */ getSourceTypes() { if ( this.externalType === "asset" && this.dependencyMeta && /** @type {AssetDependencyMeta} */ (this.dependencyMeta).sourceType === "css-url" ) { return CSS_URL_TYPES; } else if (this.externalType === "css-import") { return CSS_IMPORT_TYPES; }
return JS_TYPES; }
/** * @param {LibIdentOptions} options options * @returns {LibIdent | null} an identifier for library inclusion */ libIdent(options) { return this.userRequest; }
/** * @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 this.externalType === "css-import" ? true : chunkGraph.getNumberOfEntryModules(chunk) > 0; }
/** * @returns {string} a unique identifier of the module */ identifier() { return `external ${this._resolveExternalType(this.externalType)} ${JSON.stringify(this.request)}`; }
/** * @param {RequestShortener} requestShortener the request shortener * @returns {string} a user readable identifier of the module */ readableIdentifier(requestShortener) { return `external ${JSON.stringify(this.request)}`; }
/** * @param {NeedBuildContext} context context info * @param {NeedBuildCallback} 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 {BuildCallback} callback callback function * @returns {void} */ build(options, compilation, resolver, fs, callback) { this.buildMeta = { async: false, exportsType: undefined }; this.buildInfo = { strict: true, topLevelDeclarations: new Set(), javascriptModule: compilation.outputOptions.module }; const { request, externalType } = this._getRequestAndExternalType(); this.buildMeta.exportsType = "dynamic"; let canMangle = false; this.clearDependenciesAndBlocks(); switch (externalType) { case "this": this.buildInfo.strict = false; break; case "system": if (!Array.isArray(request) || request.length === 1) { this.buildMeta.exportsType = "namespace"; canMangle = true; } break; case "module": if (this.buildInfo.javascriptModule) { if (!Array.isArray(request) || request.length === 1) { this.buildMeta.exportsType = "namespace"; canMangle = true; } } else { this.buildMeta.async = true; EnvironmentNotSupportAsyncWarning.check( this, compilation.runtimeTemplate, "external module" ); if (!Array.isArray(request) || request.length === 1) { this.buildMeta.exportsType = "namespace"; canMangle = false; } } break; case "script": this.buildMeta.async = true; EnvironmentNotSupportAsyncWarning.check( this, compilation.runtimeTemplate, "external script" ); break; case "promise": this.buildMeta.async = true; EnvironmentNotSupportAsyncWarning.check( this, compilation.runtimeTemplate, "external promise" ); break; case "import": this.buildMeta.async = true; EnvironmentNotSupportAsyncWarning.check( this, compilation.runtimeTemplate, "external import" ); if (!Array.isArray(request) || request.length === 1) { this.buildMeta.exportsType = "namespace"; canMangle = false; } break; } this.addDependency(new StaticExportsDependency(true, canMangle)); callback(); }
/** * restore unsafe cache data * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching */ restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) { this._restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory); }
/** * @param {ConcatenationBailoutReasonContext} context context * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated */ getConcatenationBailoutReason(context) { switch (this.externalType) { case "amd": case "amd-require": case "umd": case "umd2": case "system": case "jsonp": return `${this.externalType} externals can't be concatenated`; } return undefined; }
_getRequestAndExternalType() { let { request, externalType } = this; if (typeof request === "object" && !Array.isArray(request)) { request = request[externalType]; } externalType = this._resolveExternalType(externalType); return { request, externalType }; }
/** * Resolve the detailed external type from the raw external type. * e.g. resolve "module" or "import" from "module-import" type * @param {string} externalType raw external type * @returns {string} resolved external type */ _resolveExternalType(externalType) { if (externalType === "module-import") { if ( this.dependencyMeta && /** @type {ImportDependencyMeta} */ (this.dependencyMeta).externalType ) { return /** @type {ImportDependencyMeta} */ (this.dependencyMeta) .externalType; } return "module"; } else if (externalType === "asset") { if ( this.dependencyMeta && /** @type {AssetDependencyMeta} */ (this.dependencyMeta).sourceType ) { return /** @type {AssetDependencyMeta} */ (this.dependencyMeta) .sourceType; }
return "asset"; }
return externalType; }
/** * @private * @param {string | string[]} request request * @param {string} externalType the external type * @param {RuntimeTemplate} runtimeTemplate the runtime template * @param {ModuleGraph} moduleGraph the module graph * @param {ChunkGraph} chunkGraph the chunk graph * @param {RuntimeSpec} runtime the runtime * @param {DependencyMeta | undefined} dependencyMeta the dependency meta * @param {ConcatenationScope=} concatenationScope concatenationScope * @returns {SourceData} the source data */ _getSourceData( request, externalType, runtimeTemplate, moduleGraph, chunkGraph, runtime, dependencyMeta, concatenationScope ) { switch (externalType) { case "this": case "window": case "self": return getSourceForGlobalVariableExternal(request, this.externalType); case "global": return getSourceForGlobalVariableExternal( request, runtimeTemplate.globalObject ); case "commonjs": case "commonjs2": case "commonjs-module": case "commonjs-static": return getSourceForCommonJsExternal(request); case "node-commonjs": return /** @type {BuildInfo} */ (this.buildInfo).javascriptModule ? getSourceForCommonJsExternalInNodeModule(request, runtimeTemplate) : getSourceForCommonJsExternal(request); case "amd": case "amd-require": case "umd": case "umd2": case "system": case "jsonp": { const id = chunkGraph.getModuleId(this); return getSourceForAmdOrUmdExternal( id !== null ? id : this.identifier(), this.isOptional(moduleGraph), request, runtimeTemplate ); } case "import": return getSourceForImportExternal( request, runtimeTemplate, /** @type {ImportDependencyMeta} */ (dependencyMeta) ); case "script": return getSourceForScriptExternal(request, runtimeTemplate); case "module": { if (!(/** @type {BuildInfo} */ (this.buildInfo).javascriptModule)) { if (!runtimeTemplate.supportsDynamicImport()) { throw new Error( `The target environment doesn't support dynamic import() syntax so it's not possible to use external type 'module' within a script${ runtimeTemplate.supportsEcmaScriptModuleSyntax() ? "\nDid you mean to build a EcmaScript Module ('output.module: true')?" : "" }`
); } return getSourceForImportExternal( request, runtimeTemplate, /** @type {ImportDependencyMeta} */ (dependencyMeta) ); } if (!runtimeTemplate.supportsEcmaScriptModuleSyntax()) { throw new Error( "The target environment doesn't support EcmaScriptModule syntax so it's not possible to use external type 'module'" ); } return getSourceForModuleExternal( request, moduleGraph.getExportsInfo(this), runtime, runtimeTemplate, /** @type {ImportDependencyMeta} */ (dependencyMeta), concatenationScope ); } case "var": case "promise": case "const": case "let": case "assign": default: return getSourceForDefaultCase( this.isOptional(moduleGraph), request, runtimeTemplate ); } }
/** * @param {CodeGenerationContext} context context for code generation * @returns {CodeGenerationResult} result */ codeGeneration({ runtimeTemplate, moduleGraph, chunkGraph, runtime, concatenationScope }) { const { request, externalType } = this._getRequestAndExternalType(); switch (externalType) { case "asset": { const sources = new Map(); sources.set( "javascript", new RawSource(`module.exports = ${JSON.stringify(request)};`) ); const data = new Map(); data.set("url", { javascript: request }); return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data }; } case "css-url": { const sources = new Map(); const data = new Map(); data.set("url", { "css-url": request }); return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data }; } case "css-import": { const sources = new Map(); const dependencyMeta = /** @type {CssImportDependencyMeta} */ ( this.dependencyMeta ); const layer = dependencyMeta.layer !== undefined ? ` layer(${dependencyMeta.layer})` : ""; const supports = dependencyMeta.supports ? ` supports(${dependencyMeta.supports})` : ""; const media = dependencyMeta.media ? ` ${dependencyMeta.media}` : ""; sources.set( "css-import", new RawSource( `@import url(${JSON.stringify( request )})${layer}${supports}${media};`
) ); return { sources, runtimeRequirements: EMPTY_RUNTIME_REQUIREMENTS }; } default: { const sourceData = this._getSourceData( request, externalType, runtimeTemplate, moduleGraph, chunkGraph, runtime, this.dependencyMeta, concatenationScope );
// sourceString can be empty str only when there is concatenationScope
let sourceString = sourceData.expression; if (sourceData.iife) { sourceString = `(function() { return ${sourceString}; }())`; }
const specifiers = sourceData.specifiers; if (specifiers) { sourceString = ""; const scope = /** @type {ConcatenationScope} */ (concatenationScope); for (const [specifier, finalName] of specifiers) { scope.registerRawExport(specifier, finalName); } } else if (concatenationScope) { sourceString = `${runtimeTemplate.renderConst()} ${ConcatenationScope.NAMESPACE_OBJECT_EXPORT} = ${sourceString};`; concatenationScope.registerNamespaceExport( ConcatenationScope.NAMESPACE_OBJECT_EXPORT ); } else { sourceString = `module.exports = ${sourceString};`; } if (sourceData.init) { sourceString = `${sourceData.init}\n${sourceString}`; }
let data; if (sourceData.chunkInitFragments) { data = new Map(); data.set("chunkInitFragments", sourceData.chunkInitFragments); }
const sources = new Map(); if (this.useSourceMap || this.useSimpleSourceMap) { sources.set( "javascript", new OriginalSource(sourceString, this.identifier()) ); } else { sources.set("javascript", new RawSource(sourceString)); }
let runtimeRequirements = sourceData.runtimeRequirements; if (!concatenationScope) { if (!runtimeRequirements) { runtimeRequirements = RUNTIME_REQUIREMENTS; } else { const set = new Set(runtimeRequirements); set.add(RuntimeGlobals.module); runtimeRequirements = set; } }
return { sources, runtimeRequirements: runtimeRequirements || EMPTY_RUNTIME_REQUIREMENTS, data }; } } }
/** * @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) { const { chunkGraph } = context; hash.update( `${this._resolveExternalType(this.externalType)}${JSON.stringify(this.request)}${this.isOptional( chunkGraph.moduleGraph )}`
); super.updateHash(hash, context); }
/** * @param {ObjectSerializerContext} context context */ serialize(context) { const { write } = context;
write(this.request); write(this.externalType); write(this.userRequest); write(this.dependencyMeta);
super.serialize(context); }
/** * @param {ObjectDeserializerContext} context context */ deserialize(context) { const { read } = context;
this.request = read(); this.externalType = read(); this.userRequest = read(); this.dependencyMeta = read();
super.deserialize(context); }}
makeSerializable(ExternalModule, "webpack/lib/ExternalModule");
module.exports = ExternalModule;module.exports.ModuleExternalInitFragment = ModuleExternalInitFragment;module.exports.getExternalModuleNodeCommonjsInitFragment = getExternalModuleNodeCommonjsInitFragment;
|