ExternalModule.js 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { SyncBailHook } = require("tapable");
  7. const { OriginalSource, RawSource } = require("webpack-sources");
  8. const ConcatenationScope = require("./ConcatenationScope");
  9. const { UsageState } = require("./ExportsInfo");
  10. const InitFragment = require("./InitFragment");
  11. const Module = require("./Module");
  12. const {
  13. ASSET_URL_TYPE,
  14. ASSET_URL_TYPES,
  15. CSS_IMPORT_TYPES,
  16. JAVASCRIPT_TYPE,
  17. JAVASCRIPT_TYPES
  18. } = require("./ModuleSourceTypeConstants");
  19. const { JAVASCRIPT_MODULE_TYPE_DYNAMIC } = require("./ModuleTypeConstants");
  20. const RuntimeGlobals = require("./RuntimeGlobals");
  21. const Template = require("./Template");
  22. const WebpackError = require("./WebpackError");
  23. const { DEFAULTS } = require("./config/defaults");
  24. const { ImportPhaseUtils } = require("./dependencies/ImportPhase");
  25. const StaticExportsDependency = require("./dependencies/StaticExportsDependency");
  26. const { coreModules } = require("./node/nodeBuiltins");
  27. const createHash = require("./util/createHash");
  28. const createHooksRegistry = require("./util/createHooksRegistry");
  29. const extractUrlAndGlobal = require("./util/extractUrlAndGlobal");
  30. const makeSerializable = require("./util/makeSerializable");
  31. const memoize = require("./util/memoize");
  32. const { propertyAccess } = require("./util/property");
  33. const { register } = require("./util/serialization");
  34. const getEnvironmentNotSupportAsyncWarning = memoize(() =>
  35. require("./errors/EnvironmentNotSupportAsyncWarning")
  36. );
  37. /** @import { Source } from "webpack-sources" */
  38. /**
  39. * @import {
  40. * ExternalsType,
  41. * HashFunction,
  42. * ExternalItemInterop as ExternalInterop
  43. * } from "../declarations/WebpackOptions"
  44. */
  45. /**
  46. * @import {
  47. * WebpackOptionsNormalizedWithDefaults as WebpackOptions
  48. * } from "./config/defaults"
  49. */
  50. /** @import Chunk from "./Chunk" */
  51. /** @import ChunkGraph, { ModuleId } from "./ChunkGraph" */
  52. /** @import Compilation, { UnsafeCacheData } from "./Compilation" */
  53. /** @import { UpdateHashContext } from "./Dependency" */
  54. /** @import ExportsInfo from "./ExportsInfo" */
  55. /** @import { GenerateContext } from "./Generator" */
  56. /**
  57. * @import {
  58. * BuildMeta,
  59. * BuildCallback,
  60. * BuildInfo,
  61. * CodeGenerationContext,
  62. * CodeGenerationResult,
  63. * CodeGenerationResultData,
  64. * ConcatenationBailoutReasonContext,
  65. * LibIdentOptions,
  66. * LibIdent,
  67. * NeedBuildCallback,
  68. * NeedBuildContext,
  69. * RuntimeRequirements,
  70. * ReadOnlyRuntimeRequirements,
  71. * Sources,
  72. * SourceTypes
  73. * } from "./Module"
  74. */
  75. /** @import ModuleGraph from "./ModuleGraph" */
  76. /** @import { ConnectionState } from "./ModuleGraphConnection" */
  77. /** @import NormalModuleFactory from "./NormalModuleFactory" */
  78. /** @import RequestShortener from "./RequestShortener" */
  79. /** @import { ResolverWithOptions } from "./ResolverFactory" */
  80. /** @import RuntimeTemplate from "./RuntimeTemplate" */
  81. /**
  82. * @import {
  83. * ChunkRenderContext
  84. * } from "./javascript/JavascriptModulesPlugin"
  85. */
  86. /** @import { ImportAttributes } from "./javascript/JavascriptParser" */
  87. /** @import { ImportPhaseType } from "./dependencies/ImportPhase" */
  88. /** @typedef {import("./serialization/ObjectMiddleware").ObjectDeserializerContext<[ExternalModuleRequest, ExternalsType, string, DependencyMeta | undefined, ExternalInterop | undefined, boolean | undefined]>} ObjectDeserializerContext */
  89. /** @typedef {import("./serialization/ObjectMiddleware").ObjectSerializerContext<[ExternalModuleRequest, ExternalsType, string, DependencyMeta | undefined, ExternalInterop | undefined, boolean | undefined]>} ObjectSerializerContext */
  90. /** @import Hash from "./util/Hash" */
  91. /** @import { InputFileSystem } from "./util/fs" */
  92. /** @import { RuntimeSpec } from "./util/runtime" */
  93. /** @typedef {{ attributes?: ImportAttributes, phase?: ImportPhaseType, externalType: "import" | "module" | undefined }} ImportDependencyMeta */
  94. /** @typedef {{ layer?: string, supports?: string, media?: string }} CssImportDependencyMeta */
  95. /** @typedef {{ sourceType: "asset-url" | "css-url" }} AssetDependencyMeta */
  96. /** @typedef {ImportDependencyMeta | CssImportDependencyMeta | AssetDependencyMeta} DependencyMeta */
  97. /**
  98. * Defines the source data type used by this module.
  99. * @typedef {object} SourceData
  100. * @property {boolean=} iife
  101. * @property {string=} init
  102. * @property {string} expression
  103. * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments
  104. * @property {ReadOnlyRuntimeRequirements=} runtimeRequirements
  105. * @property {[string, string][]=} specifiers
  106. */
  107. /** @typedef {true | [string, string][]} Imported */
  108. /** @type {RuntimeRequirements} */
  109. const RUNTIME_REQUIREMENTS = new Set([RuntimeGlobals.module]);
  110. /** @type {RuntimeRequirements} */
  111. const RUNTIME_REQUIREMENTS_FOR_SCRIPT = new Set([RuntimeGlobals.loadScript]);
  112. /** @type {RuntimeRequirements} */
  113. const RUNTIME_REQUIREMENTS_FOR_MODULE = new Set([
  114. RuntimeGlobals.definePropertyGetters
  115. ]);
  116. /** @type {RuntimeRequirements} */
  117. const EMPTY_RUNTIME_REQUIREMENTS = new Set();
  118. const NODE_PREFIX = "node:";
  119. // externals of these types are wired by the library wrapper, which does its own per-key lookup on object externals
  120. const LIBRARY_WIRED_EXTERNAL_TYPES = new Set([
  121. "amd",
  122. "amd-require",
  123. "umd",
  124. "umd2",
  125. "system",
  126. "jsonp"
  127. ]);
  128. // External types that emit a node.js-resolvable specifier (`require`/`import`).
  129. const NODE_RESOLVING_EXTERNAL_TYPES = new Set([
  130. "commonjs",
  131. "commonjs2",
  132. "commonjs-module",
  133. "commonjs-static",
  134. "node-commonjs",
  135. "import",
  136. "module"
  137. ]);
  138. /**
  139. * Normalizes a node.js core module specifier for the target. Strips `node:`
  140. * when the target can't resolve a prefixed request, adds `node:` for a universal
  141. * bundle (which may run on deno/bun where the prefix is required), and otherwise
  142. * keeps the author's original notation.
  143. * @param {string | string[]} request the external request
  144. * @param {ExternalsType} externalType the resolved external type
  145. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  146. * @returns {string | string[]} the normalized request
  147. */
  148. const normalizeNodeCoreModuleRequest = (
  149. request,
  150. externalType,
  151. runtimeTemplate
  152. ) => {
  153. if (!NODE_RESOLVING_EXTERNAL_TYPES.has(externalType)) return request;
  154. const name = Array.isArray(request) ? request[0] : request;
  155. if (typeof name !== "string") return request;
  156. /**
  157. * @param {string} next replacement specifier
  158. * @returns {string | string[]} request with the specifier swapped
  159. */
  160. const withName = (next) =>
  161. Array.isArray(request) ? [next, ...request.slice(1)] : next;
  162. if (
  163. runtimeTemplate.outputOptions.environment.nodePrefixForCoreModules === false
  164. ) {
  165. if (!name.startsWith(NODE_PREFIX)) return request;
  166. const stripped = name.slice(NODE_PREFIX.length);
  167. return coreModules.has(stripped) ? withName(stripped) : request;
  168. }
  169. if (runtimeTemplate.isUniversalTarget() && !name.startsWith(NODE_PREFIX)) {
  170. return coreModules.has(name) ? withName(NODE_PREFIX + name) : request;
  171. }
  172. return request;
  173. };
  174. /**
  175. * Gets source for global variable external.
  176. * @param {string | string[]} variableName the variable name or path
  177. * @param {string} type the module system
  178. * @returns {SourceData} the generated source
  179. */
  180. const getSourceForGlobalVariableExternal = (variableName, type) => {
  181. if (!Array.isArray(variableName)) {
  182. // make it an array as the look up works the same basically
  183. variableName = [variableName];
  184. }
  185. // needed for e.g. window["some"]["thing"]
  186. const objectLookup = variableName
  187. .map((r) => `[${JSON.stringify(r)}]`)
  188. .join("");
  189. return {
  190. iife: type === "this",
  191. expression: `${type}${objectLookup}`
  192. };
  193. };
  194. /** @typedef {string | string[]} ModuleAndSpecifiers */
  195. /**
  196. * Gets source for common js external.
  197. * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request
  198. * @returns {SourceData} the generated source
  199. */
  200. const getSourceForCommonJsExternal = (moduleAndSpecifiers) => {
  201. if (!Array.isArray(moduleAndSpecifiers)) {
  202. return {
  203. expression: `require(${JSON.stringify(moduleAndSpecifiers)})`
  204. };
  205. }
  206. const moduleName = moduleAndSpecifiers[0];
  207. return {
  208. expression: `require(${JSON.stringify(moduleName)})${propertyAccess(
  209. moduleAndSpecifiers,
  210. 1
  211. )}`
  212. };
  213. };
  214. /**
  215. * Gets external module node commonjs init fragment.
  216. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  217. * @param {boolean=} universal target may also run outside node (e.g. `["node", "web"]`)
  218. * @returns {InitFragment<ChunkRenderContext>} code
  219. */
  220. const getExternalModuleNodeCommonjsInitFragment = (
  221. runtimeTemplate,
  222. universal = false
  223. ) => {
  224. const importMetaName = runtimeTemplate.outputOptions.importMetaName;
  225. const moduleId = runtimeTemplate.renderNodePrefixForCoreModule("module");
  226. if (!universal) {
  227. return new InitFragment(
  228. `import { createRequire as __WEBPACK_EXTERNAL_createRequire } from ${moduleId};\n${runtimeTemplate.renderConst()} __WEBPACK_EXTERNAL_createRequire_require = __WEBPACK_EXTERNAL_createRequire(${importMetaName}.url);\n`,
  229. InitFragment.STAGE_HARMONY_IMPORTS,
  230. 0,
  231. "external module node-commonjs"
  232. );
  233. }
  234. // defensively obtain `createRequire` so the universal bundle still loads off node
  235. const content = `${runtimeTemplate.renderConst()} __WEBPACK_EXTERNAL_createRequire_require = ${runtimeTemplate.getBuiltinModule(
  236. moduleId,
  237. `.createRequire(${importMetaName}.url)`
  238. )};\n`;
  239. return new InitFragment(
  240. content,
  241. InitFragment.STAGE_HARMONY_IMPORTS,
  242. 0,
  243. "external module node-commonjs universal"
  244. );
  245. };
  246. /**
  247. * Gets source for common js external in node module.
  248. * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request
  249. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  250. * @param {boolean=} universal target may also run outside node (e.g. `["node", "web"]`)
  251. * @returns {SourceData} the generated source
  252. */
  253. const getSourceForCommonJsExternalInNodeModule = (
  254. moduleAndSpecifiers,
  255. runtimeTemplate,
  256. universal = false
  257. ) => {
  258. const chunkInitFragments = [
  259. getExternalModuleNodeCommonjsInitFragment(runtimeTemplate, universal)
  260. ];
  261. if (!Array.isArray(moduleAndSpecifiers)) {
  262. return {
  263. chunkInitFragments,
  264. expression: `__WEBPACK_EXTERNAL_createRequire_require(${JSON.stringify(
  265. moduleAndSpecifiers
  266. )})`
  267. };
  268. }
  269. const moduleName = moduleAndSpecifiers[0];
  270. return {
  271. chunkInitFragments,
  272. expression: `__WEBPACK_EXTERNAL_createRequire_require(${JSON.stringify(
  273. moduleName
  274. )})${propertyAccess(moduleAndSpecifiers, 1)}`
  275. };
  276. };
  277. /**
  278. * A phase is syntax the target has to read, with no form to fall back to. Reported
  279. * like the `import()` check beside it, so the build fails rather than the bundle.
  280. * @param {ImportPhaseType | undefined} phase the phase the reference asks for
  281. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  282. * @returns {void}
  283. */
  284. const checkPhaseIsSupported = (phase, runtimeTemplate) => {
  285. if (
  286. ImportPhaseUtils.isDefer(phase) &&
  287. !runtimeTemplate.supportsDeferImport()
  288. ) {
  289. throw new Error(
  290. "The target environment doesn't support 'import defer', so an external cannot be imported in the defer phase. Set 'output.environment.deferImport' when the target reads it."
  291. );
  292. }
  293. if (
  294. ImportPhaseUtils.isSource(phase) &&
  295. !runtimeTemplate.supportsSourceImport()
  296. ) {
  297. throw new Error(
  298. "The target environment doesn't support 'import source', so an external cannot be imported in the source phase. Set 'output.environment.sourceImport' when the target reads it."
  299. );
  300. }
  301. };
  302. /**
  303. * Gets source for import external.
  304. * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request
  305. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  306. * @param {ImportDependencyMeta=} dependencyMeta the dependency meta
  307. * @returns {SourceData} the generated source
  308. */
  309. const getSourceForImportExternal = (
  310. moduleAndSpecifiers,
  311. runtimeTemplate,
  312. dependencyMeta
  313. ) => {
  314. const baseImportName = runtimeTemplate.outputOptions.importFunctionName;
  315. if (
  316. !runtimeTemplate.supportsDynamicImport() &&
  317. (baseImportName === "import" || baseImportName === "module-import")
  318. ) {
  319. throw new Error(
  320. "The target environment doesn't support 'import()' so it's not possible to use external type 'import'"
  321. );
  322. }
  323. const phase = dependencyMeta && dependencyMeta.phase;
  324. checkPhaseIsSupported(phase, runtimeTemplate);
  325. // `import.defer(…)` and `import.source(…)` are only valid forms of the
  326. // native `import(…)` function, so we only emit the phase suffix when the
  327. // importFunctionName is the default `"import"`. Anything else has no phase
  328. // form at all, and dropping it would silently import eagerly instead.
  329. if (
  330. baseImportName !== "import" &&
  331. (ImportPhaseUtils.isDefer(phase) || ImportPhaseUtils.isSource(phase))
  332. ) {
  333. throw new Error(
  334. `'import.defer' and 'import.source' are forms of the native 'import()', so an external cannot be imported in a phase while 'output.importFunctionName' is '${baseImportName}'`
  335. );
  336. }
  337. const importName = ImportPhaseUtils.isDefer(phase)
  338. ? "import.defer"
  339. : ImportPhaseUtils.isSource(phase)
  340. ? "import.source"
  341. : baseImportName;
  342. const attributes =
  343. dependencyMeta && dependencyMeta.attributes
  344. ? dependencyMeta.attributes._isLegacyAssert
  345. ? `, { assert: ${JSON.stringify(
  346. dependencyMeta.attributes,
  347. importAssertionReplacer
  348. )} }`
  349. : `, { with: ${JSON.stringify(dependencyMeta.attributes)} }`
  350. : "";
  351. // `import.source(…)` resolves to the source object itself, while every other
  352. // external here resolves to a namespace. Consumers unwrap `default` to reach a
  353. // source, so hand them that shape rather than a value they read `default` off.
  354. const asNamespace = ImportPhaseUtils.isSource(phase)
  355. ? `.then(${runtimeTemplate.returningFunction('{ "default": m }', "m")})`
  356. : "";
  357. if (!Array.isArray(moduleAndSpecifiers)) {
  358. return {
  359. expression: `${importName}(${JSON.stringify(
  360. moduleAndSpecifiers
  361. )}${attributes})${asNamespace};`
  362. };
  363. }
  364. if (moduleAndSpecifiers.length === 1) {
  365. return {
  366. expression: `${importName}(${JSON.stringify(
  367. moduleAndSpecifiers[0]
  368. )}${attributes})${asNamespace};`
  369. };
  370. }
  371. const moduleName = moduleAndSpecifiers[0];
  372. return {
  373. expression: `${importName}(${JSON.stringify(
  374. moduleName
  375. )}${attributes}).then(${runtimeTemplate.returningFunction(
  376. `module${propertyAccess(moduleAndSpecifiers, 1)}`,
  377. "module"
  378. )});`
  379. };
  380. };
  381. /**
  382. * Import assertion replacer.
  383. * @param {string} key key
  384. * @param {ImportAttributes | string | boolean | undefined} value value
  385. * @returns {ImportAttributes | string | boolean | undefined} replaced value
  386. */
  387. const importAssertionReplacer = (key, value) => {
  388. if (key === "_isLegacyAssert") {
  389. return;
  390. }
  391. return value;
  392. };
  393. /**
  394. * Represents ModuleExternalInitFragment.
  395. * @extends {InitFragment<GenerateContext>}
  396. */
  397. class ModuleExternalInitFragment extends InitFragment {
  398. /**
  399. * Creates an instance of ModuleExternalInitFragment.
  400. * @param {string} request import source
  401. * @param {Imported} imported the imported specifiers
  402. * @param {string=} ident recomputed ident
  403. * @param {ImportDependencyMeta=} dependencyMeta the dependency meta
  404. * @param {HashFunction=} hashFunction the hash function to use
  405. */
  406. constructor(
  407. request,
  408. imported,
  409. ident,
  410. dependencyMeta,
  411. hashFunction = DEFAULTS.HASH_FUNCTION
  412. ) {
  413. if (ident === undefined) {
  414. ident = Template.toIdentifier(request);
  415. if (ident !== request) {
  416. ident += `_${createHash(hashFunction)
  417. .update(request)
  418. .digest("hex")
  419. .slice(0, 8)}`;
  420. }
  421. // One request in two phases is two imports, so the phase must reach the dedupe
  422. // key and the binding name — otherwise one silently replaces the other.
  423. const phase = dependencyMeta && dependencyMeta.phase;
  424. if (ImportPhaseUtils.isDefer(phase)) {
  425. ident += "_defer";
  426. } else if (ImportPhaseUtils.isSource(phase)) {
  427. ident += "_source";
  428. }
  429. }
  430. super(
  431. "",
  432. InitFragment.STAGE_HARMONY_IMPORTS,
  433. 0,
  434. `external module import ${ident} ${
  435. imported === true ? imported : imported.join(" ")
  436. }`
  437. );
  438. /** @type {string} */
  439. this._ident = ident;
  440. /** @type {string} */
  441. this._request = request;
  442. /** @type {ImportDependencyMeta | undefined} */
  443. this._dependencyMeta = dependencyMeta;
  444. /** @type {string} */
  445. this._identifier = this.buildIdentifier(ident);
  446. /** @type {Imported} */
  447. this._imported = this.buildImported(imported);
  448. }
  449. /**
  450. * Returns imported.
  451. * @returns {Imported} imported
  452. */
  453. getImported() {
  454. return this._imported;
  455. }
  456. /**
  457. * Updates imported using the provided imported.
  458. * @param {Imported} imported imported
  459. */
  460. setImported(imported) {
  461. this._imported = imported;
  462. }
  463. /**
  464. * Returns the source code that will be included as initialization code.
  465. * @param {GenerateContext} context context
  466. * @returns {string | Source | undefined} the source code that will be included as initialization code
  467. */
  468. getContent(context) {
  469. const {
  470. _dependencyMeta: dependencyMeta,
  471. _imported: imported,
  472. _request: request,
  473. _identifier: identifier
  474. } = this;
  475. const attributes =
  476. dependencyMeta && dependencyMeta.attributes
  477. ? dependencyMeta.attributes._isLegacyAssert
  478. ? ` assert ${JSON.stringify(
  479. dependencyMeta.attributes,
  480. importAssertionReplacer
  481. )}`
  482. : ` with ${JSON.stringify(dependencyMeta.attributes)}`
  483. : "";
  484. const phase = dependencyMeta && dependencyMeta.phase;
  485. checkPhaseIsSupported(phase, context.runtimeTemplate);
  486. let content = "";
  487. if (ImportPhaseUtils.isSource(phase) && imported === true) {
  488. // There is no `import source * as ns` form: the source phase binds one
  489. // identifier, so it stands in for the namespace the other branches build.
  490. content = `import source ${identifier} from ${JSON.stringify(
  491. request
  492. )}${attributes};\n`;
  493. } else if (imported === true) {
  494. // namespace
  495. const phaseKeyword = ImportPhaseUtils.isDefer(phase) ? "defer " : "";
  496. content = `import ${phaseKeyword}* as ${identifier} from ${JSON.stringify(
  497. request
  498. )}${attributes};\n`;
  499. } else if (imported.length === 0) {
  500. // just import, no use
  501. content = `import ${JSON.stringify(request)}${attributes};\n`;
  502. } else if (
  503. ImportPhaseUtils.isSource(phase) &&
  504. imported.length === 1 &&
  505. imported[0][0] === "default"
  506. ) {
  507. // `import source x from "…"` — the source-phase form binds the source
  508. // object directly to a single identifier (no namespace, no destructuring).
  509. content = `import source ${imported[0][1]} from ${JSON.stringify(
  510. request
  511. )}${attributes};\n`;
  512. } else {
  513. content = `import { ${imported
  514. .map(([name, finalName]) => {
  515. if (name !== finalName) {
  516. return `${name} as ${finalName}`;
  517. }
  518. return name;
  519. })
  520. .join(", ")} } from ${JSON.stringify(request)}${attributes};\n`;
  521. }
  522. return content;
  523. }
  524. getNamespaceIdentifier() {
  525. return this._identifier;
  526. }
  527. /**
  528. * Returns identifier.
  529. * @param {string} ident ident
  530. * @returns {string} identifier
  531. */
  532. buildIdentifier(ident) {
  533. return `__WEBPACK_EXTERNAL_MODULE_${ident}__`;
  534. }
  535. /**
  536. * Returns normalized imported.
  537. * @param {Imported} imported imported
  538. * @returns {Imported} normalized imported
  539. */
  540. buildImported(imported) {
  541. if (Array.isArray(imported)) {
  542. return imported.map(([name]) => {
  543. const ident = `${this._ident}_${name}`;
  544. return [name, this.buildIdentifier(ident)];
  545. });
  546. }
  547. return imported;
  548. }
  549. }
  550. register(
  551. ModuleExternalInitFragment,
  552. "webpack/lib/ExternalModule",
  553. "ModuleExternalInitFragment",
  554. {
  555. serialize(obj, { write }) {
  556. write(obj._request);
  557. write(obj._imported);
  558. write(obj._ident);
  559. write(obj._dependencyMeta);
  560. },
  561. deserialize({ read }) {
  562. return new ModuleExternalInitFragment(read(), read(), read(), read());
  563. }
  564. }
  565. );
  566. /**
  567. * Generates module remapping.
  568. * @param {string} input input
  569. * @param {ExportsInfo} exportsInfo the exports info
  570. * @param {RuntimeSpec=} runtime the runtime
  571. * @param {RuntimeTemplate=} runtimeTemplate the runtime template
  572. * @returns {string | undefined} the module remapping
  573. */
  574. const generateModuleRemapping = (
  575. input,
  576. exportsInfo,
  577. runtime,
  578. runtimeTemplate
  579. ) => {
  580. if (exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused) {
  581. /** @type {string[]} */
  582. const properties = [];
  583. for (const exportInfo of exportsInfo.orderedExports) {
  584. const used = exportInfo.getUsedName(exportInfo.name, runtime);
  585. if (!used) continue;
  586. const nestedInfo = exportInfo.getNestedExportsInfo();
  587. if (nestedInfo) {
  588. const nestedExpr = generateModuleRemapping(
  589. `${input}${propertyAccess([exportInfo.name])}`,
  590. nestedInfo
  591. );
  592. if (nestedExpr) {
  593. properties.push(`[${JSON.stringify(used)}]: y(${nestedExpr})`);
  594. continue;
  595. }
  596. }
  597. properties.push(
  598. `[${JSON.stringify(used)}]: ${
  599. /** @type {RuntimeTemplate} */ (runtimeTemplate).returningFunction(
  600. `${input}${propertyAccess([exportInfo.name])}`
  601. )
  602. }`
  603. );
  604. }
  605. return `x({ ${properties.join(", ")} })`;
  606. }
  607. };
  608. /**
  609. * Gets source for module external.
  610. * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request
  611. * @param {ExportsInfo} exportsInfo exports info of this module
  612. * @param {RuntimeSpec} runtime the runtime
  613. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  614. * @param {ImportDependencyMeta} dependencyMeta the dependency meta
  615. * @param {ConcatenationScope=} concatenationScope concatenationScope
  616. * @returns {SourceData} the generated source
  617. */
  618. const getSourceForModuleExternal = (
  619. moduleAndSpecifiers,
  620. exportsInfo,
  621. runtime,
  622. runtimeTemplate,
  623. dependencyMeta,
  624. concatenationScope
  625. ) => {
  626. const phase = dependencyMeta && dependencyMeta.phase;
  627. /** @type {Imported} */
  628. let imported = true;
  629. if (concatenationScope) {
  630. const usedExports = exportsInfo.getUsedExports(runtime);
  631. switch (usedExports) {
  632. case true:
  633. case null:
  634. // unknown exports
  635. imported = true;
  636. break;
  637. case false:
  638. // no used exports
  639. imported = [];
  640. break;
  641. default:
  642. imported = [...usedExports.entries()];
  643. }
  644. }
  645. if (!Array.isArray(moduleAndSpecifiers)) {
  646. moduleAndSpecifiers = [moduleAndSpecifiers];
  647. }
  648. // Return to `namespace` when the external request includes a specific export
  649. if (moduleAndSpecifiers.length > 1) {
  650. imported = true;
  651. }
  652. // `import defer …` is only valid as `import defer * as ns from "…"`, so
  653. // keep the namespace form even if usage analysis would otherwise narrow
  654. // the import down to specific names. Defer + concatenation is semantically
  655. // at odds (lazy vs. eager), so we preserve the user-written shape here.
  656. if (ImportPhaseUtils.isDefer(phase)) {
  657. imported = true;
  658. }
  659. // A source phase binds `default` alone. With nothing used the list would be empty
  660. // and emit `import "…"`, evaluating the module whose source was asked for instead.
  661. if (
  662. ImportPhaseUtils.isSource(phase) &&
  663. Array.isArray(imported) &&
  664. imported.length === 0
  665. ) {
  666. imported = [["default", "default"]];
  667. }
  668. const initFragment = new ModuleExternalInitFragment(
  669. moduleAndSpecifiers[0],
  670. imported,
  671. undefined,
  672. dependencyMeta,
  673. runtimeTemplate.outputOptions.hashFunction
  674. );
  675. const normalizedImported = initFragment.getImported();
  676. const baseAccess = `${initFragment.getNamespaceIdentifier()}${propertyAccess(
  677. moduleAndSpecifiers,
  678. 1
  679. )}`;
  680. let expression = baseAccess;
  681. // A source-phase binding is not a namespace object, so nothing about it can be
  682. // remapped export by export — the binding itself is what the reference reads.
  683. const useNamespace = imported === true && !ImportPhaseUtils.isSource(phase);
  684. /** @type {undefined | string} */
  685. let moduleRemapping;
  686. if (useNamespace) {
  687. moduleRemapping = generateModuleRemapping(
  688. baseAccess,
  689. exportsInfo,
  690. runtime,
  691. runtimeTemplate
  692. );
  693. expression = moduleRemapping || baseAccess;
  694. }
  695. return {
  696. expression,
  697. init: moduleRemapping
  698. ? `${runtimeTemplate.renderConst()} x = ${runtimeTemplate.basicFunction(
  699. "y",
  700. `${runtimeTemplate.renderConst()} x = {}; ${
  701. RuntimeGlobals.definePropertyGetters
  702. }(x, y); return x`
  703. )} \n${runtimeTemplate.renderConst()} y = ${runtimeTemplate.returningFunction(
  704. runtimeTemplate.returningFunction("x"),
  705. "x"
  706. )}`
  707. : undefined,
  708. specifiers: normalizedImported === true ? undefined : normalizedImported,
  709. runtimeRequirements: moduleRemapping
  710. ? RUNTIME_REQUIREMENTS_FOR_MODULE
  711. : undefined,
  712. chunkInitFragments: [
  713. /** @type {InitFragment<EXPECTED_ANY>} */ (initFragment)
  714. ]
  715. };
  716. };
  717. /**
  718. * Gets source for script external.
  719. * @param {string | string[]} urlAndGlobal the script request
  720. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  721. * @returns {SourceData} the generated source
  722. */
  723. const getSourceForScriptExternal = (urlAndGlobal, runtimeTemplate) => {
  724. if (typeof urlAndGlobal === "string") {
  725. urlAndGlobal = extractUrlAndGlobal(urlAndGlobal);
  726. }
  727. const url = urlAndGlobal[0];
  728. const globalName = urlAndGlobal[1];
  729. return {
  730. init: `${runtimeTemplate.renderConst()} __webpack_error__ = new Error();`,
  731. expression: `new Promise(${runtimeTemplate.basicFunction(
  732. "resolve, reject",
  733. [
  734. `if(typeof ${globalName} !== "undefined") return resolve();`,
  735. `${RuntimeGlobals.loadScript}(${JSON.stringify(
  736. url
  737. )}, ${runtimeTemplate.basicFunction("event", [
  738. `if(typeof ${globalName} !== "undefined") return resolve();`,
  739. `${runtimeTemplate.renderConst()} errorType = event && (event.type === 'load' ? 'missing' : event.type);`,
  740. `${runtimeTemplate.renderConst()} realSrc = event && event.target && event.target.src;`,
  741. "__webpack_error__.message = 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';",
  742. "__webpack_error__.name = 'ScriptExternalLoadError';",
  743. "__webpack_error__.type = errorType;",
  744. "__webpack_error__.request = realSrc;",
  745. "__webpack_error__.event = event;",
  746. "reject(__webpack_error__);"
  747. ])}, ${JSON.stringify(globalName)});`
  748. ]
  749. )}).then(${runtimeTemplate.returningFunction(
  750. `${globalName}${propertyAccess(urlAndGlobal, 2)}`
  751. )})`,
  752. runtimeRequirements: RUNTIME_REQUIREMENTS_FOR_SCRIPT
  753. };
  754. };
  755. /**
  756. * Gets source for amd-async external. Loads the module at runtime via the
  757. * asynchronous AMD `require([...])` API and exposes it as an async module,
  758. * so no AMD library wrapper around the chunk is needed.
  759. * @param {string | string[]} request the request path
  760. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  761. * @returns {SourceData} the generated source
  762. */
  763. const getSourceForAmdAsyncExternal = (request, runtimeTemplate) => {
  764. if (!Array.isArray(request)) {
  765. request = [request];
  766. }
  767. const { library } = runtimeTemplate.outputOptions;
  768. const amdRequire =
  769. library && library.amdContainer
  770. ? `${library.amdContainer}.require`
  771. : "require";
  772. return {
  773. expression: `new Promise(${runtimeTemplate.basicFunction(
  774. "resolve, reject",
  775. [
  776. `if (typeof ${amdRequire} !== "function") return reject(new Error(${JSON.stringify(
  777. `AMD 'require' is not available to load external module ${request[0]}`
  778. )}));`,
  779. `${amdRequire}(${JSON.stringify([
  780. request[0]
  781. ])}, ${runtimeTemplate.basicFunction(
  782. "module",
  783. `resolve(module${propertyAccess(request, 1)});`
  784. )}, reject);`
  785. ]
  786. )})`
  787. };
  788. };
  789. /**
  790. * Checks external variable.
  791. * @param {string} variableName the variable name to check
  792. * @param {string} request the request path
  793. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  794. * @returns {string} the generated source
  795. */
  796. const checkExternalVariable = (variableName, request, runtimeTemplate) =>
  797. `if(typeof ${variableName} === 'undefined') { ${runtimeTemplate.throwMissingModuleErrorBlock(
  798. { request }
  799. )} }\n`;
  800. /**
  801. * Gets source for amd or umd external.
  802. * @param {ModuleId | string} id the module id
  803. * @param {boolean} optional true, if the module is optional
  804. * @param {string | string[]} request the request path
  805. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  806. * @returns {SourceData} the generated source
  807. */
  808. const getSourceForAmdOrUmdExternal = (
  809. id,
  810. optional,
  811. request,
  812. runtimeTemplate
  813. ) => {
  814. const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
  815. `${id}`
  816. )}__`;
  817. return {
  818. init: optional
  819. ? checkExternalVariable(
  820. externalVariable,
  821. Array.isArray(request) ? request.join(".") : request,
  822. runtimeTemplate
  823. )
  824. : undefined,
  825. expression: externalVariable
  826. };
  827. };
  828. /**
  829. * Gets source for default case.
  830. * @param {boolean} optional true, if the module is optional
  831. * @param {string | string[]} request the request path
  832. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  833. * @returns {SourceData} the generated source
  834. */
  835. const getSourceForDefaultCase = (optional, request, runtimeTemplate) => {
  836. if (!Array.isArray(request)) {
  837. // make it an array as the look up works the same basically
  838. request = [request];
  839. }
  840. const variableName = request[0];
  841. const objectLookup = propertyAccess(request, 1);
  842. return {
  843. init: optional
  844. ? checkExternalVariable(variableName, request.join("."), runtimeTemplate)
  845. : undefined,
  846. expression: `${variableName}${objectLookup}`
  847. };
  848. };
  849. /** @typedef {Record<string, string | string[]>} RequestRecord */
  850. /** @typedef {string | string[] | RequestRecord} ExternalModuleRequest */
  851. const createCompilationHooks = () => ({
  852. /**
  853. * @type {SyncBailHook<[Chunk, Compilation], boolean>}
  854. * @since 5.106.0
  855. */
  856. chunkCondition: new SyncBailHook(["chunk", "compilation"])
  857. });
  858. /**
  859. * @typedef {ReturnType<typeof createCompilationHooks>} ExternalModuleHooks
  860. */
  861. /**
  862. * Defines the build info properties specific to external modules.
  863. * @typedef {object} KnownExternalModuleBuildInfo
  864. * @property {boolean=} javascriptModule true when emitting an ESM external (`output.module`)
  865. */
  866. /** @typedef {BuildInfo & KnownExternalModuleBuildInfo} ExternalModuleBuildInfo */
  867. class ExternalModule extends Module {
  868. /**
  869. * Creates an instance of ExternalModule.
  870. * @param {ExternalModuleRequest} request request
  871. * @param {ExternalsType} type type
  872. * @param {string} userRequest user request
  873. * @param {DependencyMeta=} dependencyMeta dependency meta
  874. * @param {ExternalInterop=} interop how the external's exports interoperate with ES module imports
  875. * @param {boolean=} sideEffects whether importing the external has side effects (undefined = assume it has)
  876. */
  877. constructor(
  878. request,
  879. type,
  880. userRequest,
  881. dependencyMeta,
  882. interop,
  883. sideEffects
  884. ) {
  885. super(JAVASCRIPT_MODULE_TYPE_DYNAMIC, null);
  886. // Redeclared with the external module specific shape
  887. /** @type {ExternalModuleBuildInfo | undefined} */
  888. this.buildInfo = undefined;
  889. // Info from Factory
  890. /** @type {ExternalModuleRequest} */
  891. this.request = request;
  892. /** @type {ExternalsType} */
  893. this.externalType = type;
  894. /** @type {string} */
  895. this.userRequest = userRequest;
  896. /** @type {DependencyMeta=} */
  897. this.dependencyMeta = dependencyMeta;
  898. /** @type {ExternalInterop | undefined} interop shape of the external's exports (undefined = importer-driven default) */
  899. this.interop = interop;
  900. /** @type {boolean | undefined} declared side-effects state (undefined = assume side effects, webpack can't analyze an external) */
  901. this.sideEffects = sideEffects;
  902. if (sideEffects !== undefined) {
  903. this.factoryMeta = { sideEffectFree: !sideEffects };
  904. }
  905. }
  906. /**
  907. * Returns the source types this module can generate.
  908. * @returns {SourceTypes} types available (do not mutate)
  909. */
  910. getSourceTypes() {
  911. // resolved, so a type rendering no javascript is never reported as a
  912. // javascript module — that would emit a dead `false` factory in the chunk
  913. const type = this._resolveExternalType(this.externalType);
  914. // TODO webpack 6 drop "css-url" once the alias is removed
  915. if (type === ASSET_URL_TYPE || type === "css-url") {
  916. return ASSET_URL_TYPES;
  917. }
  918. if (type === "css-import") return CSS_IMPORT_TYPES;
  919. return JAVASCRIPT_TYPES;
  920. }
  921. /**
  922. * Gets the library identifier.
  923. * @param {LibIdentOptions} options options
  924. * @returns {LibIdent | null} an identifier for library inclusion
  925. */
  926. libIdent(options) {
  927. return this.userRequest;
  928. }
  929. /**
  930. * Returns true if the module can be placed in the chunk.
  931. * @param {Chunk} chunk the chunk which condition should be checked
  932. * @param {Compilation} compilation the compilation
  933. * @returns {boolean} true if the module can be placed in the chunk
  934. */
  935. chunkCondition(chunk, compilation) {
  936. const { chunkCondition } = ExternalModule.getCompilationHooks(compilation);
  937. const condition = chunkCondition.call(chunk, compilation);
  938. if (condition !== undefined) return condition;
  939. const type = this._resolveExternalType(this.externalType);
  940. // For `import()` externals, keep them in the initial chunk to avoid loading
  941. // them asynchronously twice and to improve runtime performance.
  942. if (["css-import", "module"].includes(type)) {
  943. return true;
  944. }
  945. return compilation.chunkGraph.getNumberOfEntryModules(chunk) > 0;
  946. }
  947. /**
  948. * Gets side effects connection state.
  949. * @param {ModuleGraph} moduleGraph the module graph
  950. * @returns {ConnectionState} how this module should be connected to referencing modules when consumed for side-effects only
  951. */
  952. getSideEffectsConnectionState(moduleGraph) {
  953. if (this.factoryMeta !== undefined) {
  954. if (this.factoryMeta.sideEffectFree) return false;
  955. if (this.factoryMeta.sideEffectFree === false) return true;
  956. }
  957. return true;
  958. }
  959. /**
  960. * Returns the unique identifier used to reference this module.
  961. * @returns {string} a unique identifier of the module
  962. */
  963. identifier() {
  964. let id = `external ${this._resolveExternalType(
  965. this.externalType
  966. )} ${JSON.stringify(this.request)}`;
  967. const meta = /** @type {ImportDependencyMeta | undefined} */ (
  968. this.dependencyMeta
  969. );
  970. if (meta) {
  971. if (meta.phase) {
  972. id += `|phase=${ImportPhaseUtils.stringify(meta.phase)}`;
  973. }
  974. if (meta.attributes) {
  975. id += `|attributes=${JSON.stringify(meta.attributes)}`;
  976. }
  977. }
  978. if (this.interop) id += `|interop=${this.interop}`;
  979. // two externals for the same target with a different side-effects state
  980. // must not be merged into one module
  981. if (this.sideEffects !== undefined) {
  982. id += `|sideEffects=${this.sideEffects}`;
  983. }
  984. return id;
  985. }
  986. /**
  987. * Returns a human-readable identifier for this module.
  988. * @param {RequestShortener} requestShortener the request shortener
  989. * @returns {string} a user readable identifier of the module
  990. */
  991. readableIdentifier(requestShortener) {
  992. return `external ${JSON.stringify(this.request)}`;
  993. }
  994. /**
  995. * Checks whether the module needs to be rebuilt for the current build state.
  996. * @param {NeedBuildContext} context context info
  997. * @param {NeedBuildCallback} callback callback function, returns true, if the module needs a rebuild
  998. * @returns {void}
  999. */
  1000. needBuild(context, callback) {
  1001. return callback(null, !this.buildMeta);
  1002. }
  1003. /**
  1004. * Builds the module using the provided compilation context.
  1005. * @param {WebpackOptions} options webpack options
  1006. * @param {Compilation} compilation the compilation
  1007. * @param {ResolverWithOptions} resolver the resolver
  1008. * @param {InputFileSystem} fs the file system
  1009. * @param {BuildCallback} callback callback function
  1010. * @returns {void}
  1011. */
  1012. build(options, compilation, resolver, fs, callback) {
  1013. this.buildMeta = {
  1014. async: false,
  1015. exportsType: undefined
  1016. };
  1017. this.buildInfo = {
  1018. strict: true,
  1019. topLevelDeclarations: new Set(),
  1020. javascriptModule: compilation.outputOptions.module
  1021. };
  1022. const { request, externalType } = this._getRequestAndExternalType();
  1023. if (
  1024. request === undefined &&
  1025. typeof this.request === "object" &&
  1026. !Array.isArray(this.request) &&
  1027. !LIBRARY_WIRED_EXTERNAL_TYPES.has(this.externalType)
  1028. ) {
  1029. this.addError(
  1030. new WebpackError(
  1031. `Missing external configuration for type "${
  1032. this.externalType
  1033. }" in external ${JSON.stringify(
  1034. this.request
  1035. )}. Add a ${JSON.stringify(
  1036. this.externalType
  1037. )} entry to it or set 'output.externalsType'/'output.library.type' to one of: ${Object.keys(
  1038. this.request
  1039. )
  1040. .map((key) => JSON.stringify(key))
  1041. .join(", ")}`
  1042. )
  1043. );
  1044. }
  1045. this.buildMeta.exportsType = "dynamic";
  1046. let canMangle = false;
  1047. this.clearDependenciesAndBlocks();
  1048. switch (externalType) {
  1049. case "this":
  1050. this.buildInfo.strict = false;
  1051. break;
  1052. case "system":
  1053. if (!Array.isArray(request) || request.length === 1) {
  1054. this.buildMeta.exportsType = "namespace";
  1055. canMangle = true;
  1056. }
  1057. break;
  1058. case "module":
  1059. if (this.buildInfo.javascriptModule) {
  1060. if (!Array.isArray(request) || request.length === 1) {
  1061. this.buildMeta.exportsType = "namespace";
  1062. canMangle = true;
  1063. }
  1064. } else {
  1065. this.buildMeta.async = true;
  1066. getEnvironmentNotSupportAsyncWarning().check(
  1067. this,
  1068. compilation.runtimeTemplate,
  1069. "external module"
  1070. );
  1071. if (!Array.isArray(request) || request.length === 1) {
  1072. this.buildMeta.exportsType = "namespace";
  1073. canMangle = false;
  1074. }
  1075. }
  1076. break;
  1077. case "script":
  1078. this.buildMeta.async = true;
  1079. getEnvironmentNotSupportAsyncWarning().check(
  1080. this,
  1081. compilation.runtimeTemplate,
  1082. "external script"
  1083. );
  1084. break;
  1085. case "promise":
  1086. this.buildMeta.async = true;
  1087. getEnvironmentNotSupportAsyncWarning().check(
  1088. this,
  1089. compilation.runtimeTemplate,
  1090. "external promise"
  1091. );
  1092. break;
  1093. case "amd-async":
  1094. this.buildMeta.async = true;
  1095. getEnvironmentNotSupportAsyncWarning().check(
  1096. this,
  1097. compilation.runtimeTemplate,
  1098. "external amd-async"
  1099. );
  1100. break;
  1101. case "import":
  1102. this.buildMeta.async = true;
  1103. getEnvironmentNotSupportAsyncWarning().check(
  1104. this,
  1105. compilation.runtimeTemplate,
  1106. "external import"
  1107. );
  1108. if (!Array.isArray(request) || request.length === 1) {
  1109. this.buildMeta.exportsType = "namespace";
  1110. canMangle = false;
  1111. }
  1112. break;
  1113. }
  1114. // Opt-in override for how the external's exports interoperate with ESM
  1115. // imports, independent of the importer's strictness (see Rollup's
  1116. // `output.interop`). Only meaningful for a single-request external.
  1117. if (this.interop && (!Array.isArray(request) || request.length === 1)) {
  1118. if (this.interop === "esModule") {
  1119. // external already is an ES module namespace: `default` unboxes to `.default`
  1120. this.buildMeta.exportsType = "namespace";
  1121. } else {
  1122. // "default": treat as CommonJS, `default` is the whole exports (Node.js semantics)
  1123. this.buildMeta.exportsType = "default";
  1124. this.buildMeta.defaultObject = "redirect";
  1125. }
  1126. canMangle = false;
  1127. }
  1128. this.addDependency(new StaticExportsDependency(true, canMangle));
  1129. callback();
  1130. }
  1131. /**
  1132. * restore unsafe cache data
  1133. * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData
  1134. * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching
  1135. */
  1136. restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) {
  1137. this._restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory);
  1138. }
  1139. /**
  1140. * Returns the reason this module cannot be concatenated, when one exists.
  1141. * @param {ConcatenationBailoutReasonContext} context context
  1142. * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated
  1143. */
  1144. getConcatenationBailoutReason(context) {
  1145. switch (this.externalType) {
  1146. case "amd":
  1147. case "amd-require":
  1148. case "umd":
  1149. case "umd2":
  1150. case "system":
  1151. case "jsonp":
  1152. return `${this.externalType} externals can't be concatenated`;
  1153. }
  1154. return undefined;
  1155. }
  1156. /**
  1157. * @returns {boolean} true, when it may be wrapped
  1158. */
  1159. canBeWrappedInConcatenation() {
  1160. if (/** @type {BuildMeta} */ (this.buildMeta).async) {
  1161. return false;
  1162. }
  1163. // every other synchronous type is a plain expression; only "module"
  1164. // renders as a hoisted `import` declaration, and passing it the
  1165. // concatenation scope is what narrows it to named specifiers
  1166. return this._resolveExternalType(this.externalType) !== "module";
  1167. }
  1168. /**
  1169. * Get request and external type.
  1170. * @private
  1171. * @returns {{ request: string | string[], externalType: ExternalsType }} the request and external type
  1172. */
  1173. _getRequestAndExternalType() {
  1174. let { request, externalType } = this;
  1175. if (typeof request === "object" && !Array.isArray(request)) {
  1176. request = request[externalType];
  1177. }
  1178. externalType = this._resolveExternalType(externalType);
  1179. return { request, externalType };
  1180. }
  1181. /**
  1182. * Resolve the detailed external type from the raw external type.
  1183. * e.g. resolve "module" or "import" from "module-import" type
  1184. * @param {ExternalsType} externalType raw external type
  1185. * @returns {ExternalsType} resolved external type
  1186. */
  1187. _resolveExternalType(externalType) {
  1188. if (externalType === "module-import") {
  1189. if (
  1190. this.dependencyMeta &&
  1191. /** @type {ImportDependencyMeta} */
  1192. (this.dependencyMeta).externalType
  1193. ) {
  1194. return /** @type {ImportDependencyMeta} */ (this.dependencyMeta)
  1195. .externalType;
  1196. }
  1197. return "module";
  1198. } else if (
  1199. // TODO webpack 6 drop "css-url" once the alias is removed
  1200. externalType === "asset" ||
  1201. externalType === ASSET_URL_TYPE ||
  1202. externalType === "css-url"
  1203. ) {
  1204. // the consumer decides: a css `url()` reads the url out of the module
  1205. // (marked by the factory), a `new URL()` requires the `asset` wrapper
  1206. if (
  1207. this.dependencyMeta &&
  1208. /** @type {AssetDependencyMeta} */
  1209. (this.dependencyMeta).sourceType
  1210. ) {
  1211. return /** @type {AssetDependencyMeta} */ (this.dependencyMeta)
  1212. .sourceType;
  1213. }
  1214. return "asset";
  1215. }
  1216. return externalType;
  1217. }
  1218. /**
  1219. * Returns the source data.
  1220. * @private
  1221. * @param {string | string[]} request request
  1222. * @param {ExternalsType} externalType the external type
  1223. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  1224. * @param {ModuleGraph} moduleGraph the module graph
  1225. * @param {ChunkGraph} chunkGraph the chunk graph
  1226. * @param {RuntimeSpec} runtime the runtime
  1227. * @param {DependencyMeta | undefined} dependencyMeta the dependency meta
  1228. * @param {ConcatenationScope=} concatenationScope concatenationScope
  1229. * @returns {SourceData} the source data
  1230. */
  1231. _getSourceData(
  1232. request,
  1233. externalType,
  1234. runtimeTemplate,
  1235. moduleGraph,
  1236. chunkGraph,
  1237. runtime,
  1238. dependencyMeta,
  1239. concatenationScope
  1240. ) {
  1241. request = normalizeNodeCoreModuleRequest(
  1242. request,
  1243. externalType,
  1244. runtimeTemplate
  1245. );
  1246. switch (externalType) {
  1247. case "this":
  1248. case "window":
  1249. case "self":
  1250. return getSourceForGlobalVariableExternal(request, this.externalType);
  1251. case "global":
  1252. return getSourceForGlobalVariableExternal(
  1253. request,
  1254. runtimeTemplate.globalObject
  1255. );
  1256. case "commonjs":
  1257. case "commonjs2":
  1258. case "commonjs-module":
  1259. case "commonjs-static":
  1260. case "node-commonjs": {
  1261. const { node } = runtimeTemplate.compilation.options.externalsPresets;
  1262. // ESM has no `require`; load via `createRequire` when the target is node
  1263. const createRequireInModule =
  1264. /** @type {BuildInfo} */ (this.buildInfo).javascriptModule &&
  1265. (externalType === "node-commonjs" || Boolean(node));
  1266. if (!createRequireInModule) {
  1267. return getSourceForCommonJsExternal(request);
  1268. }
  1269. // for a universal target (e.g. `["node", "web"]`) load defensively so the browser doesn't crash
  1270. return getSourceForCommonJsExternalInNodeModule(
  1271. request,
  1272. runtimeTemplate,
  1273. runtimeTemplate.isUniversalTarget()
  1274. );
  1275. }
  1276. case "amd-async":
  1277. return getSourceForAmdAsyncExternal(request, runtimeTemplate);
  1278. case "amd":
  1279. case "amd-require":
  1280. case "umd":
  1281. case "umd2":
  1282. case "system":
  1283. case "jsonp": {
  1284. const id = chunkGraph.getModuleId(this);
  1285. return getSourceForAmdOrUmdExternal(
  1286. id !== null ? id : this.identifier(),
  1287. this.isOptional(moduleGraph),
  1288. request,
  1289. runtimeTemplate
  1290. );
  1291. }
  1292. case "import":
  1293. return getSourceForImportExternal(
  1294. request,
  1295. runtimeTemplate,
  1296. /** @type {ImportDependencyMeta} */ (dependencyMeta)
  1297. );
  1298. case "script":
  1299. return getSourceForScriptExternal(request, runtimeTemplate);
  1300. case "module": {
  1301. if (!(/** @type {BuildInfo} */ (this.buildInfo).javascriptModule)) {
  1302. if (!runtimeTemplate.supportsDynamicImport()) {
  1303. throw new Error(
  1304. `The target environment doesn't support dynamic import() syntax so it's not possible to use external type 'module' within a script${
  1305. runtimeTemplate.supportsEcmaScriptModuleSyntax()
  1306. ? "\nDid you mean to build a EcmaScript Module ('output.module: true')?"
  1307. : ""
  1308. }`
  1309. );
  1310. }
  1311. return getSourceForImportExternal(
  1312. request,
  1313. runtimeTemplate,
  1314. /** @type {ImportDependencyMeta} */ (dependencyMeta)
  1315. );
  1316. }
  1317. if (!runtimeTemplate.supportsEcmaScriptModuleSyntax()) {
  1318. throw new Error(
  1319. "The target environment doesn't support EcmaScriptModule syntax so it's not possible to use external type 'module'"
  1320. );
  1321. }
  1322. return getSourceForModuleExternal(
  1323. request,
  1324. moduleGraph.getExportsInfo(this),
  1325. runtime,
  1326. runtimeTemplate,
  1327. /** @type {ImportDependencyMeta} */ (dependencyMeta),
  1328. concatenationScope
  1329. );
  1330. }
  1331. case "var":
  1332. case "promise":
  1333. case "assign":
  1334. default:
  1335. return getSourceForDefaultCase(
  1336. this.isOptional(moduleGraph),
  1337. request,
  1338. runtimeTemplate
  1339. );
  1340. }
  1341. }
  1342. /**
  1343. * Generates code and runtime requirements for this module.
  1344. * @param {CodeGenerationContext} context context for code generation
  1345. * @returns {CodeGenerationResult} result
  1346. */
  1347. codeGeneration({
  1348. runtimeTemplate,
  1349. moduleGraph,
  1350. chunkGraph,
  1351. runtime,
  1352. concatenationScope
  1353. }) {
  1354. const { request, externalType } = this._getRequestAndExternalType();
  1355. switch (externalType) {
  1356. case "asset": {
  1357. /** @type {Sources} */
  1358. const sources = new Map();
  1359. sources.set(
  1360. JAVASCRIPT_TYPE,
  1361. new RawSource(`module.exports = ${JSON.stringify(request)};`)
  1362. );
  1363. /** @type {CodeGenerationResultData} */
  1364. const data = new Map();
  1365. data.set("url", { javascript: /** @type {string} */ (request) });
  1366. return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data };
  1367. }
  1368. // TODO webpack 6 remove "css-url" alias
  1369. case "css-url":
  1370. case "asset-url": {
  1371. /** @type {Sources} */
  1372. const sources = new Map();
  1373. /** @type {CodeGenerationResultData} */
  1374. const data = new Map();
  1375. data.set("url", { [ASSET_URL_TYPE]: /** @type {string} */ (request) });
  1376. return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data };
  1377. }
  1378. case "css-import": {
  1379. /** @type {Sources} */
  1380. const sources = new Map();
  1381. const dependencyMeta = /** @type {CssImportDependencyMeta} */ (
  1382. this.dependencyMeta
  1383. );
  1384. const layer =
  1385. dependencyMeta.layer !== undefined
  1386. ? ` layer(${dependencyMeta.layer})`
  1387. : "";
  1388. const supports = dependencyMeta.supports
  1389. ? ` supports(${dependencyMeta.supports})`
  1390. : "";
  1391. const media = dependencyMeta.media ? ` ${dependencyMeta.media}` : "";
  1392. sources.set(
  1393. "css-import",
  1394. new RawSource(
  1395. `@import url(${JSON.stringify(
  1396. request
  1397. )})${layer}${supports}${media};`
  1398. )
  1399. );
  1400. return {
  1401. sources,
  1402. runtimeRequirements: EMPTY_RUNTIME_REQUIREMENTS
  1403. };
  1404. }
  1405. default: {
  1406. // A wrapped external runs as a module body inside the wrapper, so it
  1407. // renders the plain `module.exports =` form: its exports are read
  1408. // through the wrapper accessor, not through a shared-scope binding.
  1409. const wrapped = Boolean(
  1410. concatenationScope &&
  1411. /** @type {ConcatenationScope} */ (concatenationScope).isWrapped()
  1412. );
  1413. const sourceData = this._getSourceData(
  1414. request,
  1415. externalType,
  1416. runtimeTemplate,
  1417. moduleGraph,
  1418. chunkGraph,
  1419. runtime,
  1420. this.dependencyMeta,
  1421. wrapped ? undefined : concatenationScope
  1422. );
  1423. // sourceString can be empty str only when there is concatenationScope
  1424. let sourceString = sourceData.expression;
  1425. if (sourceData.iife) {
  1426. sourceString = `(function() { return ${sourceString}; }())`;
  1427. }
  1428. const specifiers = sourceData.specifiers;
  1429. if (specifiers) {
  1430. sourceString = "";
  1431. const scope = /** @type {ConcatenationScope} */ (concatenationScope);
  1432. for (const [specifier, finalName] of specifiers) {
  1433. // the hoisted `import { x as finalName }` binding is a top-level
  1434. // name of the chunk, reserve it before members get renamed
  1435. scope.usedNames.add(finalName);
  1436. scope.registerRawExport(specifier, finalName);
  1437. }
  1438. } else if (concatenationScope && !wrapped) {
  1439. sourceString = `${runtimeTemplate.renderConst()} ${
  1440. ConcatenationScope.NAMESPACE_OBJECT_EXPORT
  1441. } = ${sourceString};`;
  1442. concatenationScope.registerNamespaceExport(
  1443. ConcatenationScope.NAMESPACE_OBJECT_EXPORT
  1444. );
  1445. } else {
  1446. sourceString = `module.exports = ${sourceString};`;
  1447. }
  1448. if (sourceData.init) {
  1449. sourceString = `${sourceData.init}\n${sourceString}`;
  1450. }
  1451. /** @type {undefined | CodeGenerationResultData} */
  1452. let data;
  1453. if (sourceData.chunkInitFragments) {
  1454. data = new Map();
  1455. data.set("chunkInitFragments", sourceData.chunkInitFragments);
  1456. }
  1457. /** @type {Sources} */
  1458. const sources = new Map();
  1459. if (this.useSourceMap || this.useSimpleSourceMap) {
  1460. sources.set(
  1461. JAVASCRIPT_TYPE,
  1462. new OriginalSource(sourceString, this.identifier())
  1463. );
  1464. } else {
  1465. sources.set(JAVASCRIPT_TYPE, new RawSource(sourceString));
  1466. }
  1467. let runtimeRequirements = sourceData.runtimeRequirements;
  1468. if (!concatenationScope) {
  1469. if (!runtimeRequirements) {
  1470. runtimeRequirements = RUNTIME_REQUIREMENTS;
  1471. } else {
  1472. const set = new Set(runtimeRequirements);
  1473. set.add(RuntimeGlobals.module);
  1474. runtimeRequirements = set;
  1475. }
  1476. }
  1477. return {
  1478. sources,
  1479. runtimeRequirements:
  1480. runtimeRequirements || EMPTY_RUNTIME_REQUIREMENTS,
  1481. data
  1482. };
  1483. }
  1484. }
  1485. }
  1486. /**
  1487. * Returns the estimated size for the requested source type.
  1488. * @param {string=} type the source type for which the size should be estimated
  1489. * @returns {number} the estimated size of the module (must be non-zero)
  1490. */
  1491. size(type) {
  1492. return 42;
  1493. }
  1494. /**
  1495. * Updates the hash with the data contributed by this instance.
  1496. * @param {Hash} hash the hash used to track dependencies
  1497. * @param {UpdateHashContext} context context
  1498. * @returns {void}
  1499. */
  1500. updateHash(hash, context) {
  1501. const { chunkGraph } = context;
  1502. hash.update(
  1503. `${this._resolveExternalType(this.externalType)}${JSON.stringify(
  1504. this.request
  1505. )}${this.isOptional(chunkGraph.moduleGraph)}`
  1506. );
  1507. const meta = /** @type {ImportDependencyMeta | undefined} */ (
  1508. this.dependencyMeta
  1509. );
  1510. if (meta) {
  1511. if (meta.phase) {
  1512. hash.update(`|phase=${ImportPhaseUtils.stringify(meta.phase)}`);
  1513. }
  1514. if (meta.attributes) {
  1515. hash.update(`|attributes=${JSON.stringify(meta.attributes)}`);
  1516. }
  1517. }
  1518. if (this.interop) hash.update(`|interop=${this.interop}`);
  1519. if (this.sideEffects !== undefined) {
  1520. hash.update(`|sideEffects=${this.sideEffects}`);
  1521. }
  1522. super.updateHash(hash, context);
  1523. }
  1524. /**
  1525. * Serializes this instance into the provided serializer context.
  1526. * @param {ObjectSerializerContext} context context
  1527. */
  1528. serialize(context) {
  1529. context
  1530. .write(this.request)
  1531. .write(this.externalType)
  1532. .write(this.userRequest)
  1533. .write(this.dependencyMeta)
  1534. .write(this.interop)
  1535. .write(this.sideEffects);
  1536. super.serialize(context);
  1537. }
  1538. /**
  1539. * Restores this instance from the provided deserializer context.
  1540. * @param {ObjectDeserializerContext} context context
  1541. */
  1542. deserialize(context) {
  1543. this.request = context.read();
  1544. const c1 = context.rest;
  1545. this.externalType = c1.read();
  1546. const c2 = c1.rest;
  1547. this.userRequest = c2.read();
  1548. const c3 = c2.rest;
  1549. this.dependencyMeta = c3.read();
  1550. const c4 = c3.rest;
  1551. this.interop = c4.read();
  1552. const c5 = c4.rest;
  1553. this.sideEffects = c5.read();
  1554. super.deserialize(c5.rest);
  1555. }
  1556. }
  1557. ExternalModule.getCompilationHooks = createHooksRegistry(
  1558. createCompilationHooks
  1559. );
  1560. makeSerializable(ExternalModule, "webpack/lib/ExternalModule");
  1561. ExternalModule.ModuleExternalInitFragment = ModuleExternalInitFragment;
  1562. ExternalModule.getExternalModuleNodeCommonjsInitFragment =
  1563. getExternalModuleNodeCommonjsInitFragment;
  1564. module.exports = ExternalModule;