ExternalModule.js 28 KB

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