You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

967 lines
28 KiB

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