ExternalModule.js 22 KB

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