ExternalModule.js 23 KB

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