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;