simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

ExternalModule.js (22463B)


      1 /*
      2 	MIT License http://www.opensource.org/licenses/mit-license.php
      3 	Author Tobias Koppers @sokra
      4 */
      5 
      6 "use strict";
      7 
      8 const { OriginalSource, RawSource } = require("webpack-sources");
      9 const ConcatenationScope = require("./ConcatenationScope");
     10 const { UsageState } = require("./ExportsInfo");
     11 const InitFragment = require("./InitFragment");
     12 const Module = require("./Module");
     13 const RuntimeGlobals = require("./RuntimeGlobals");
     14 const Template = require("./Template");
     15 const StaticExportsDependency = require("./dependencies/StaticExportsDependency");
     16 const createHash = require("./util/createHash");
     17 const extractUrlAndGlobal = require("./util/extractUrlAndGlobal");
     18 const makeSerializable = require("./util/makeSerializable");
     19 const propertyAccess = require("./util/propertyAccess");
     20 const { register } = require("./util/serialization");
     21 
     22 /** @typedef {import("webpack-sources").Source} Source */
     23 /** @typedef {import("../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
     24 /** @typedef {import("./Chunk")} Chunk */
     25 /** @typedef {import("./ChunkGraph")} ChunkGraph */
     26 /** @typedef {import("./Compilation")} Compilation */
     27 /** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext */
     28 /** @typedef {import("./DependencyTemplates")} DependencyTemplates */
     29 /** @typedef {import("./ExportsInfo")} ExportsInfo */
     30 /** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
     31 /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
     32 /** @typedef {import("./Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
     33 /** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
     34 /** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
     35 /** @typedef {import("./NormalModuleFactory")} NormalModuleFactory */
     36 /** @typedef {import("./RequestShortener")} RequestShortener */
     37 /** @typedef {import("./ResolverFactory").ResolverWithOptions} ResolverWithOptions */
     38 /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
     39 /** @typedef {import("./WebpackError")} WebpackError */
     40 /** @typedef {import("./javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
     41 /** @typedef {import("./util/Hash")} Hash */
     42 /** @typedef {typeof import("./util/Hash")} HashConstructor */
     43 /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
     44 /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
     45 
     46 /**
     47  * @typedef {Object} SourceData
     48  * @property {boolean=} iife
     49  * @property {string=} init
     50  * @property {string} expression
     51  * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments
     52  * @property {ReadonlySet<string>=} runtimeRequirements
     53  */
     54 
     55 const TYPES = new Set(["javascript"]);
     56 const CSS_TYPES = new Set(["css-import"]);
     57 const RUNTIME_REQUIREMENTS = new Set([RuntimeGlobals.module]);
     58 const RUNTIME_REQUIREMENTS_FOR_SCRIPT = new Set([RuntimeGlobals.loadScript]);
     59 const RUNTIME_REQUIREMENTS_FOR_MODULE = new Set([
     60 	RuntimeGlobals.definePropertyGetters
     61 ]);
     62 const EMPTY_RUNTIME_REQUIREMENTS = new Set([]);
     63 
     64 /**
     65  * @param {string|string[]} variableName the variable name or path
     66  * @param {string} type the module system
     67  * @returns {SourceData} the generated source
     68  */
     69 const getSourceForGlobalVariableExternal = (variableName, type) => {
     70 	if (!Array.isArray(variableName)) {
     71 		// make it an array as the look up works the same basically
     72 		variableName = [variableName];
     73 	}
     74 
     75 	// needed for e.g. window["some"]["thing"]
     76 	const objectLookup = variableName.map(r => `[${JSON.stringify(r)}]`).join("");
     77 	return {
     78 		iife: type === "this",
     79 		expression: `${type}${objectLookup}`
     80 	};
     81 };
     82 
     83 /**
     84  * @param {string|string[]} moduleAndSpecifiers the module request
     85  * @returns {SourceData} the generated source
     86  */
     87 const getSourceForCommonJsExternal = moduleAndSpecifiers => {
     88 	if (!Array.isArray(moduleAndSpecifiers)) {
     89 		return {
     90 			expression: `require(${JSON.stringify(moduleAndSpecifiers)})`
     91 		};
     92 	}
     93 	const moduleName = moduleAndSpecifiers[0];
     94 	return {
     95 		expression: `require(${JSON.stringify(moduleName)})${propertyAccess(
     96 			moduleAndSpecifiers,
     97 			1
     98 		)}`
     99 	};
    100 };
    101 
    102 /**
    103  * @param {string|string[]} moduleAndSpecifiers the module request
    104  * @returns {SourceData} the generated source
    105  */
    106 const getSourceForCommonJsExternalInNodeModule = moduleAndSpecifiers => {
    107 	const chunkInitFragments = [
    108 		new InitFragment(
    109 			'import { createRequire as __WEBPACK_EXTERNAL_createRequire } from "module";\n',
    110 			InitFragment.STAGE_HARMONY_IMPORTS,
    111 			0,
    112 			"external module node-commonjs"
    113 		)
    114 	];
    115 	if (!Array.isArray(moduleAndSpecifiers)) {
    116 		return {
    117 			expression: `__WEBPACK_EXTERNAL_createRequire(import.meta.url)(${JSON.stringify(
    118 				moduleAndSpecifiers
    119 			)})`,
    120 			chunkInitFragments
    121 		};
    122 	}
    123 	const moduleName = moduleAndSpecifiers[0];
    124 	return {
    125 		expression: `__WEBPACK_EXTERNAL_createRequire(import.meta.url)(${JSON.stringify(
    126 			moduleName
    127 		)})${propertyAccess(moduleAndSpecifiers, 1)}`,
    128 		chunkInitFragments
    129 	};
    130 };
    131 
    132 /**
    133  * @param {string|string[]} moduleAndSpecifiers the module request
    134  * @param {RuntimeTemplate} runtimeTemplate the runtime template
    135  * @returns {SourceData} the generated source
    136  */
    137 const getSourceForImportExternal = (moduleAndSpecifiers, runtimeTemplate) => {
    138 	const importName = runtimeTemplate.outputOptions.importFunctionName;
    139 	if (!runtimeTemplate.supportsDynamicImport() && importName === "import") {
    140 		throw new Error(
    141 			"The target environment doesn't support 'import()' so it's not possible to use external type 'import'"
    142 		);
    143 	}
    144 	if (!Array.isArray(moduleAndSpecifiers)) {
    145 		return {
    146 			expression: `${importName}(${JSON.stringify(moduleAndSpecifiers)});`
    147 		};
    148 	}
    149 	if (moduleAndSpecifiers.length === 1) {
    150 		return {
    151 			expression: `${importName}(${JSON.stringify(moduleAndSpecifiers[0])});`
    152 		};
    153 	}
    154 	const moduleName = moduleAndSpecifiers[0];
    155 	return {
    156 		expression: `${importName}(${JSON.stringify(
    157 			moduleName
    158 		)}).then(${runtimeTemplate.returningFunction(
    159 			`module${propertyAccess(moduleAndSpecifiers, 1)}`,
    160 			"module"
    161 		)});`
    162 	};
    163 };
    164 
    165 class ModuleExternalInitFragment extends InitFragment {
    166 	/**
    167 	 * @param {string} request import source
    168 	 * @param {string=} ident recomputed ident
    169 	 * @param {string | HashConstructor=} hashFunction the hash function to use
    170 	 */
    171 	constructor(request, ident, hashFunction = "md4") {
    172 		if (ident === undefined) {
    173 			ident = Template.toIdentifier(request);
    174 			if (ident !== request) {
    175 				ident += `_${createHash(hashFunction)
    176 					.update(request)
    177 					.digest("hex")
    178 					.slice(0, 8)}`;
    179 			}
    180 		}
    181 		const identifier = `__WEBPACK_EXTERNAL_MODULE_${ident}__`;
    182 		super(
    183 			`import * as ${identifier} from ${JSON.stringify(request)};\n`,
    184 			InitFragment.STAGE_HARMONY_IMPORTS,
    185 			0,
    186 			`external module import ${ident}`
    187 		);
    188 		this._ident = ident;
    189 		this._identifier = identifier;
    190 		this._request = request;
    191 	}
    192 
    193 	getNamespaceIdentifier() {
    194 		return this._identifier;
    195 	}
    196 }
    197 
    198 register(
    199 	ModuleExternalInitFragment,
    200 	"webpack/lib/ExternalModule",
    201 	"ModuleExternalInitFragment",
    202 	{
    203 		serialize(obj, { write }) {
    204 			write(obj._request);
    205 			write(obj._ident);
    206 		},
    207 		deserialize({ read }) {
    208 			return new ModuleExternalInitFragment(read(), read());
    209 		}
    210 	}
    211 );
    212 
    213 const generateModuleRemapping = (input, exportsInfo, runtime) => {
    214 	if (exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused) {
    215 		const properties = [];
    216 		for (const exportInfo of exportsInfo.orderedExports) {
    217 			const used = exportInfo.getUsedName(exportInfo.name, runtime);
    218 			if (!used) continue;
    219 			const nestedInfo = exportInfo.getNestedExportsInfo();
    220 			if (nestedInfo) {
    221 				const nestedExpr = generateModuleRemapping(
    222 					`${input}${propertyAccess([exportInfo.name])}`,
    223 					nestedInfo
    224 				);
    225 				if (nestedExpr) {
    226 					properties.push(`[${JSON.stringify(used)}]: y(${nestedExpr})`);
    227 					continue;
    228 				}
    229 			}
    230 			properties.push(
    231 				`[${JSON.stringify(used)}]: () => ${input}${propertyAccess([
    232 					exportInfo.name
    233 				])}`
    234 			);
    235 		}
    236 		return `x({ ${properties.join(", ")} })`;
    237 	}
    238 };
    239 
    240 /**
    241  * @param {string|string[]} moduleAndSpecifiers the module request
    242  * @param {ExportsInfo} exportsInfo exports info of this module
    243  * @param {RuntimeSpec} runtime the runtime
    244  * @param {string | HashConstructor=} hashFunction the hash function to use
    245  * @returns {SourceData} the generated source
    246  */
    247 const getSourceForModuleExternal = (
    248 	moduleAndSpecifiers,
    249 	exportsInfo,
    250 	runtime,
    251 	hashFunction
    252 ) => {
    253 	if (!Array.isArray(moduleAndSpecifiers))
    254 		moduleAndSpecifiers = [moduleAndSpecifiers];
    255 	const initFragment = new ModuleExternalInitFragment(
    256 		moduleAndSpecifiers[0],
    257 		undefined,
    258 		hashFunction
    259 	);
    260 	const baseAccess = `${initFragment.getNamespaceIdentifier()}${propertyAccess(
    261 		moduleAndSpecifiers,
    262 		1
    263 	)}`;
    264 	const moduleRemapping = generateModuleRemapping(
    265 		baseAccess,
    266 		exportsInfo,
    267 		runtime
    268 	);
    269 	let expression = moduleRemapping || baseAccess;
    270 	return {
    271 		expression,
    272 		init: `var x = y => { var x = {}; ${RuntimeGlobals.definePropertyGetters}(x, y); return x; }\nvar y = x => () => x`,
    273 		runtimeRequirements: moduleRemapping
    274 			? RUNTIME_REQUIREMENTS_FOR_MODULE
    275 			: undefined,
    276 		chunkInitFragments: [initFragment]
    277 	};
    278 };
    279 
    280 /**
    281  * @param {string|string[]} urlAndGlobal the script request
    282  * @param {RuntimeTemplate} runtimeTemplate the runtime template
    283  * @returns {SourceData} the generated source
    284  */
    285 const getSourceForScriptExternal = (urlAndGlobal, runtimeTemplate) => {
    286 	if (typeof urlAndGlobal === "string") {
    287 		urlAndGlobal = extractUrlAndGlobal(urlAndGlobal);
    288 	}
    289 	const url = urlAndGlobal[0];
    290 	const globalName = urlAndGlobal[1];
    291 	return {
    292 		init: "var __webpack_error__ = new Error();",
    293 		expression: `new Promise(${runtimeTemplate.basicFunction(
    294 			"resolve, reject",
    295 			[
    296 				`if(typeof ${globalName} !== "undefined") return resolve();`,
    297 				`${RuntimeGlobals.loadScript}(${JSON.stringify(
    298 					url
    299 				)}, ${runtimeTemplate.basicFunction("event", [
    300 					`if(typeof ${globalName} !== "undefined") return resolve();`,
    301 					"var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
    302 					"var realSrc = event && event.target && event.target.src;",
    303 					"__webpack_error__.message = 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';",
    304 					"__webpack_error__.name = 'ScriptExternalLoadError';",
    305 					"__webpack_error__.type = errorType;",
    306 					"__webpack_error__.request = realSrc;",
    307 					"reject(__webpack_error__);"
    308 				])}, ${JSON.stringify(globalName)});`
    309 			]
    310 		)}).then(${runtimeTemplate.returningFunction(
    311 			`${globalName}${propertyAccess(urlAndGlobal, 2)}`
    312 		)})`,
    313 		runtimeRequirements: RUNTIME_REQUIREMENTS_FOR_SCRIPT
    314 	};
    315 };
    316 
    317 /**
    318  * @param {string} variableName the variable name to check
    319  * @param {string} request the request path
    320  * @param {RuntimeTemplate} runtimeTemplate the runtime template
    321  * @returns {string} the generated source
    322  */
    323 const checkExternalVariable = (variableName, request, runtimeTemplate) => {
    324 	return `if(typeof ${variableName} === 'undefined') { ${runtimeTemplate.throwMissingModuleErrorBlock(
    325 		{ request }
    326 	)} }\n`;
    327 };
    328 
    329 /**
    330  * @param {string|number} id the module id
    331  * @param {boolean} optional true, if the module is optional
    332  * @param {string|string[]} request the request path
    333  * @param {RuntimeTemplate} runtimeTemplate the runtime template
    334  * @returns {SourceData} the generated source
    335  */
    336 const getSourceForAmdOrUmdExternal = (
    337 	id,
    338 	optional,
    339 	request,
    340 	runtimeTemplate
    341 ) => {
    342 	const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
    343 		`${id}`
    344 	)}__`;
    345 	return {
    346 		init: optional
    347 			? checkExternalVariable(
    348 					externalVariable,
    349 					Array.isArray(request) ? request.join(".") : request,
    350 					runtimeTemplate
    351 			  )
    352 			: undefined,
    353 		expression: externalVariable
    354 	};
    355 };
    356 
    357 /**
    358  * @param {boolean} optional true, if the module is optional
    359  * @param {string|string[]} request the request path
    360  * @param {RuntimeTemplate} runtimeTemplate the runtime template
    361  * @returns {SourceData} the generated source
    362  */
    363 const getSourceForDefaultCase = (optional, request, runtimeTemplate) => {
    364 	if (!Array.isArray(request)) {
    365 		// make it an array as the look up works the same basically
    366 		request = [request];
    367 	}
    368 
    369 	const variableName = request[0];
    370 	const objectLookup = propertyAccess(request, 1);
    371 	return {
    372 		init: optional
    373 			? checkExternalVariable(variableName, request.join("."), runtimeTemplate)
    374 			: undefined,
    375 		expression: `${variableName}${objectLookup}`
    376 	};
    377 };
    378 
    379 class ExternalModule extends Module {
    380 	constructor(request, type, userRequest) {
    381 		super("javascript/dynamic", null);
    382 
    383 		// Info from Factory
    384 		/** @type {string | string[] | Record<string, string | string[]>} */
    385 		this.request = request;
    386 		/** @type {string} */
    387 		this.externalType = type;
    388 		/** @type {string} */
    389 		this.userRequest = userRequest;
    390 	}
    391 
    392 	/**
    393 	 * @returns {Set<string>} types available (do not mutate)
    394 	 */
    395 	getSourceTypes() {
    396 		return this.externalType === "css-import" ? CSS_TYPES : TYPES;
    397 	}
    398 
    399 	/**
    400 	 * @param {LibIdentOptions} options options
    401 	 * @returns {string | null} an identifier for library inclusion
    402 	 */
    403 	libIdent(options) {
    404 		return this.userRequest;
    405 	}
    406 
    407 	/**
    408 	 * @param {Chunk} chunk the chunk which condition should be checked
    409 	 * @param {Compilation} compilation the compilation
    410 	 * @returns {boolean} true, if the chunk is ok for the module
    411 	 */
    412 	chunkCondition(chunk, { chunkGraph }) {
    413 		return this.externalType === "css-import"
    414 			? true
    415 			: chunkGraph.getNumberOfEntryModules(chunk) > 0;
    416 	}
    417 
    418 	/**
    419 	 * @returns {string} a unique identifier of the module
    420 	 */
    421 	identifier() {
    422 		return `external ${this.externalType} ${JSON.stringify(this.request)}`;
    423 	}
    424 
    425 	/**
    426 	 * @param {RequestShortener} requestShortener the request shortener
    427 	 * @returns {string} a user readable identifier of the module
    428 	 */
    429 	readableIdentifier(requestShortener) {
    430 		return "external " + JSON.stringify(this.request);
    431 	}
    432 
    433 	/**
    434 	 * @param {NeedBuildContext} context context info
    435 	 * @param {function((WebpackError | null)=, boolean=): void} callback callback function, returns true, if the module needs a rebuild
    436 	 * @returns {void}
    437 	 */
    438 	needBuild(context, callback) {
    439 		return callback(null, !this.buildMeta);
    440 	}
    441 
    442 	/**
    443 	 * @param {WebpackOptions} options webpack options
    444 	 * @param {Compilation} compilation the compilation
    445 	 * @param {ResolverWithOptions} resolver the resolver
    446 	 * @param {InputFileSystem} fs the file system
    447 	 * @param {function(WebpackError=): void} callback callback function
    448 	 * @returns {void}
    449 	 */
    450 	build(options, compilation, resolver, fs, callback) {
    451 		this.buildMeta = {
    452 			async: false,
    453 			exportsType: undefined
    454 		};
    455 		this.buildInfo = {
    456 			strict: true,
    457 			topLevelDeclarations: new Set(),
    458 			module: compilation.outputOptions.module
    459 		};
    460 		const { request, externalType } = this._getRequestAndExternalType();
    461 		this.buildMeta.exportsType = "dynamic";
    462 		let canMangle = false;
    463 		this.clearDependenciesAndBlocks();
    464 		switch (externalType) {
    465 			case "this":
    466 				this.buildInfo.strict = false;
    467 				break;
    468 			case "system":
    469 				if (!Array.isArray(request) || request.length === 1) {
    470 					this.buildMeta.exportsType = "namespace";
    471 					canMangle = true;
    472 				}
    473 				break;
    474 			case "module":
    475 				if (this.buildInfo.module) {
    476 					if (!Array.isArray(request) || request.length === 1) {
    477 						this.buildMeta.exportsType = "namespace";
    478 						canMangle = true;
    479 					}
    480 				} else {
    481 					this.buildMeta.async = true;
    482 					if (!Array.isArray(request) || request.length === 1) {
    483 						this.buildMeta.exportsType = "namespace";
    484 						canMangle = false;
    485 					}
    486 				}
    487 				break;
    488 			case "script":
    489 			case "promise":
    490 				this.buildMeta.async = true;
    491 				break;
    492 			case "import":
    493 				this.buildMeta.async = true;
    494 				if (!Array.isArray(request) || request.length === 1) {
    495 					this.buildMeta.exportsType = "namespace";
    496 					canMangle = false;
    497 				}
    498 				break;
    499 		}
    500 		this.addDependency(new StaticExportsDependency(true, canMangle));
    501 		callback();
    502 	}
    503 
    504 	restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) {
    505 		this._restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory);
    506 	}
    507 
    508 	/**
    509 	 * @param {ConcatenationBailoutReasonContext} context context
    510 	 * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated
    511 	 */
    512 	getConcatenationBailoutReason({ moduleGraph }) {
    513 		switch (this.externalType) {
    514 			case "amd":
    515 			case "amd-require":
    516 			case "umd":
    517 			case "umd2":
    518 			case "system":
    519 			case "jsonp":
    520 				return `${this.externalType} externals can't be concatenated`;
    521 		}
    522 		return undefined;
    523 	}
    524 
    525 	_getRequestAndExternalType() {
    526 		let { request, externalType } = this;
    527 		if (typeof request === "object" && !Array.isArray(request))
    528 			request = request[externalType];
    529 		return { request, externalType };
    530 	}
    531 
    532 	_getSourceData(
    533 		request,
    534 		externalType,
    535 		runtimeTemplate,
    536 		moduleGraph,
    537 		chunkGraph,
    538 		runtime
    539 	) {
    540 		switch (externalType) {
    541 			case "this":
    542 			case "window":
    543 			case "self":
    544 				return getSourceForGlobalVariableExternal(request, this.externalType);
    545 			case "global":
    546 				return getSourceForGlobalVariableExternal(
    547 					request,
    548 					runtimeTemplate.globalObject
    549 				);
    550 			case "commonjs":
    551 			case "commonjs2":
    552 			case "commonjs-module":
    553 			case "commonjs-static":
    554 				return getSourceForCommonJsExternal(request);
    555 			case "node-commonjs":
    556 				return this.buildInfo.module
    557 					? getSourceForCommonJsExternalInNodeModule(request)
    558 					: getSourceForCommonJsExternal(request);
    559 			case "amd":
    560 			case "amd-require":
    561 			case "umd":
    562 			case "umd2":
    563 			case "system":
    564 			case "jsonp": {
    565 				const id = chunkGraph.getModuleId(this);
    566 				return getSourceForAmdOrUmdExternal(
    567 					id !== null ? id : this.identifier(),
    568 					this.isOptional(moduleGraph),
    569 					request,
    570 					runtimeTemplate
    571 				);
    572 			}
    573 			case "import":
    574 				return getSourceForImportExternal(request, runtimeTemplate);
    575 			case "script":
    576 				return getSourceForScriptExternal(request, runtimeTemplate);
    577 			case "module": {
    578 				if (!this.buildInfo.module) {
    579 					if (!runtimeTemplate.supportsDynamicImport()) {
    580 						throw new Error(
    581 							"The target environment doesn't support dynamic import() syntax so it's not possible to use external type 'module' within a script" +
    582 								(runtimeTemplate.supportsEcmaScriptModuleSyntax()
    583 									? "\nDid you mean to build a EcmaScript Module ('output.module: true')?"
    584 									: "")
    585 						);
    586 					}
    587 					return getSourceForImportExternal(request, runtimeTemplate);
    588 				}
    589 				if (!runtimeTemplate.supportsEcmaScriptModuleSyntax()) {
    590 					throw new Error(
    591 						"The target environment doesn't support EcmaScriptModule syntax so it's not possible to use external type 'module'"
    592 					);
    593 				}
    594 				return getSourceForModuleExternal(
    595 					request,
    596 					moduleGraph.getExportsInfo(this),
    597 					runtime,
    598 					runtimeTemplate.outputOptions.hashFunction
    599 				);
    600 			}
    601 			case "var":
    602 			case "promise":
    603 			case "const":
    604 			case "let":
    605 			case "assign":
    606 			default:
    607 				return getSourceForDefaultCase(
    608 					this.isOptional(moduleGraph),
    609 					request,
    610 					runtimeTemplate
    611 				);
    612 		}
    613 	}
    614 
    615 	/**
    616 	 * @param {CodeGenerationContext} context context for code generation
    617 	 * @returns {CodeGenerationResult} result
    618 	 */
    619 	codeGeneration({
    620 		runtimeTemplate,
    621 		moduleGraph,
    622 		chunkGraph,
    623 		runtime,
    624 		concatenationScope
    625 	}) {
    626 		const { request, externalType } = this._getRequestAndExternalType();
    627 		switch (externalType) {
    628 			case "asset": {
    629 				const sources = new Map();
    630 				sources.set(
    631 					"javascript",
    632 					new RawSource(`module.exports = ${JSON.stringify(request)};`)
    633 				);
    634 				const data = new Map();
    635 				data.set("url", request);
    636 				return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data };
    637 			}
    638 			case "css-import": {
    639 				const sources = new Map();
    640 				sources.set(
    641 					"css-import",
    642 					new RawSource(`@import url(${JSON.stringify(request)});`)
    643 				);
    644 				return {
    645 					sources,
    646 					runtimeRequirements: EMPTY_RUNTIME_REQUIREMENTS
    647 				};
    648 			}
    649 			default: {
    650 				const sourceData = this._getSourceData(
    651 					request,
    652 					externalType,
    653 					runtimeTemplate,
    654 					moduleGraph,
    655 					chunkGraph,
    656 					runtime
    657 				);
    658 
    659 				let sourceString = sourceData.expression;
    660 				if (sourceData.iife)
    661 					sourceString = `(function() { return ${sourceString}; }())`;
    662 				if (concatenationScope) {
    663 					sourceString = `${
    664 						runtimeTemplate.supportsConst() ? "const" : "var"
    665 					} ${ConcatenationScope.NAMESPACE_OBJECT_EXPORT} = ${sourceString};`;
    666 					concatenationScope.registerNamespaceExport(
    667 						ConcatenationScope.NAMESPACE_OBJECT_EXPORT
    668 					);
    669 				} else {
    670 					sourceString = `module.exports = ${sourceString};`;
    671 				}
    672 				if (sourceData.init)
    673 					sourceString = `${sourceData.init}\n${sourceString}`;
    674 
    675 				let data = undefined;
    676 				if (sourceData.chunkInitFragments) {
    677 					data = new Map();
    678 					data.set("chunkInitFragments", sourceData.chunkInitFragments);
    679 				}
    680 
    681 				const sources = new Map();
    682 				if (this.useSourceMap || this.useSimpleSourceMap) {
    683 					sources.set(
    684 						"javascript",
    685 						new OriginalSource(sourceString, this.identifier())
    686 					);
    687 				} else {
    688 					sources.set("javascript", new RawSource(sourceString));
    689 				}
    690 
    691 				let runtimeRequirements = sourceData.runtimeRequirements;
    692 				if (!concatenationScope) {
    693 					if (!runtimeRequirements) {
    694 						runtimeRequirements = RUNTIME_REQUIREMENTS;
    695 					} else {
    696 						const set = new Set(runtimeRequirements);
    697 						set.add(RuntimeGlobals.module);
    698 						runtimeRequirements = set;
    699 					}
    700 				}
    701 
    702 				return {
    703 					sources,
    704 					runtimeRequirements:
    705 						runtimeRequirements || EMPTY_RUNTIME_REQUIREMENTS,
    706 					data
    707 				};
    708 			}
    709 		}
    710 	}
    711 
    712 	/**
    713 	 * @param {string=} type the source type for which the size should be estimated
    714 	 * @returns {number} the estimated size of the module (must be non-zero)
    715 	 */
    716 	size(type) {
    717 		return 42;
    718 	}
    719 
    720 	/**
    721 	 * @param {Hash} hash the hash used to track dependencies
    722 	 * @param {UpdateHashContext} context context
    723 	 * @returns {void}
    724 	 */
    725 	updateHash(hash, context) {
    726 		const { chunkGraph } = context;
    727 		hash.update(
    728 			`${this.externalType}${JSON.stringify(this.request)}${this.isOptional(
    729 				chunkGraph.moduleGraph
    730 			)}`
    731 		);
    732 		super.updateHash(hash, context);
    733 	}
    734 
    735 	serialize(context) {
    736 		const { write } = context;
    737 
    738 		write(this.request);
    739 		write(this.externalType);
    740 		write(this.userRequest);
    741 
    742 		super.serialize(context);
    743 	}
    744 
    745 	deserialize(context) {
    746 		const { read } = context;
    747 
    748 		this.request = read();
    749 		this.externalType = read();
    750 		this.userRequest = read();
    751 
    752 		super.deserialize(context);
    753 	}
    754 }
    755 
    756 makeSerializable(ExternalModule, "webpack/lib/ExternalModule");
    757 
    758 module.exports = ExternalModule;