ExternalModule.js 22 KB

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