ConcatenatedModule.js 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const eslintScope = require("eslint-scope");
  7. const Referencer = require("eslint-scope/lib/referencer");
  8. const { SyncBailHook } = require("tapable");
  9. const {
  10. CachedSource,
  11. ConcatSource,
  12. ReplaceSource
  13. } = require("webpack-sources");
  14. const ConcatenationScope = require("../ConcatenationScope");
  15. const { UsageState } = require("../ExportsInfo");
  16. const Module = require("../Module");
  17. const {
  18. JAVASCRIPT_TYPE,
  19. JAVASCRIPT_TYPES
  20. } = require("../ModuleSourceTypeConstants");
  21. const { JAVASCRIPT_MODULE_TYPE_ESM } = require("../ModuleTypeConstants");
  22. const RuntimeGlobals = require("../RuntimeGlobals");
  23. const Template = require("../Template");
  24. const { DEFAULTS } = require("../config/defaults");
  25. const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
  26. const { ImportPhaseUtils } = require("../dependencies/ImportPhase");
  27. const JavascriptParser = require("../javascript/JavascriptParser");
  28. const {
  29. getMakeDeferredNamespaceModeFromExportsType,
  30. getOptimizedDeferredModule
  31. } = require("../runtime/MakeDeferredNamespaceObjectRuntime");
  32. const { equals } = require("../util/ArrayHelpers");
  33. const LazySet = require("../util/LazySet");
  34. const { concatComparators } = require("../util/comparators");
  35. const {
  36. RESERVED_NAMES,
  37. addScopeSymbols,
  38. findNewName,
  39. getAllReferences,
  40. getPathInAst,
  41. getUsedNamesInScopeInfo
  42. } = require("../util/concatenate");
  43. const createHash = require("../util/createHash");
  44. const { makePathsRelative } = require("../util/identifier");
  45. const makeSerializable = require("../util/makeSerializable");
  46. const propertyAccess = require("../util/propertyAccess");
  47. const { propertyName } = require("../util/propertyName");
  48. const {
  49. filterRuntime,
  50. intersectRuntime,
  51. mergeRuntimeCondition,
  52. mergeRuntimeConditionNonFalse,
  53. runtimeConditionToString,
  54. subtractRuntimeCondition
  55. } = require("../util/runtime");
  56. /** @typedef {import("eslint-scope").Reference} Reference */
  57. /** @typedef {import("eslint-scope").Scope} Scope */
  58. /** @typedef {import("eslint-scope").Variable} Variable */
  59. /** @typedef {import("webpack-sources").Source} Source */
  60. /** @typedef {import("../config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions */
  61. /** @typedef {import("../ChunkGraph")} ChunkGraph */
  62. /** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
  63. /** @typedef {import("../Compilation")} Compilation */
  64. /** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
  65. /** @typedef {import("../DependencyTemplates")} DependencyTemplates */
  66. /** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
  67. /** @typedef {import("../Module").BuildCallback} BuildCallback */
  68. /** @typedef {import("../Module").BuildInfo} BuildInfo */
  69. /** @typedef {import("../Module").FileSystemDependencies} FileSystemDependencies */
  70. /** @typedef {import("../Module").BuildMeta} BuildMeta */
  71. /** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */
  72. /** @typedef {import("../Module").CodeGenerationResultData} CodeGenerationResultData */
  73. /** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
  74. /** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
  75. /** @typedef {import("../Module").LibIdent} LibIdent */
  76. /** @typedef {import("../Module").NameForCondition} NameForCondition */
  77. /** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
  78. /** @typedef {import("../Module").RuntimeRequirements} RuntimeRequirements */
  79. /** @typedef {import("../Module").SourceTypes} SourceTypes */
  80. /** @typedef {import("../ModuleGraph")} ModuleGraph */
  81. /** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
  82. /** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
  83. /** @typedef {import("../RequestShortener")} RequestShortener */
  84. /** @typedef {import("../ResolverFactory").ResolverWithOptions} ResolverWithOptions */
  85. /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
  86. /** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
  87. /** @typedef {import("../javascript/JavascriptParser").Program} Program */
  88. /** @typedef {import("../javascript/JavascriptParser").Range} Range */
  89. /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
  90. /** @typedef {import("../util/Hash")} Hash */
  91. /** @typedef {import("../util/Hash").HashFunction} HashFunction */
  92. /** @typedef {import("../util/concatenate").UsedNames} UsedNames */
  93. /** @typedef {import("../util/concatenate").ScopeInfo} ScopeInfo */
  94. /** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
  95. /** @typedef {import("../util/identifier").AssociatedObjectForCache} AssociatedObjectForCache */
  96. /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
  97. /**
  98. * @template T
  99. * @typedef {import("../InitFragment")<T>} InitFragment
  100. */
  101. /**
  102. * @template T
  103. * @typedef {import("../util/comparators").Comparator<T>} Comparator
  104. */
  105. // fix eslint-scope to support class properties correctly
  106. // cspell:word Referencer
  107. const ReferencerClass = Referencer;
  108. if (!ReferencerClass.prototype.PropertyDefinition) {
  109. ReferencerClass.prototype.PropertyDefinition =
  110. ReferencerClass.prototype.Property;
  111. }
  112. /** @typedef {RawBinding | SymbolBinding} Binding */
  113. /** @typedef {string[]} ExportName */
  114. /**
  115. * @typedef {object} RawBinding
  116. * @property {ModuleInfo} info
  117. * @property {string} rawName
  118. * @property {string=} comment
  119. * @property {ExportName} ids
  120. * @property {ExportName} exportName
  121. */
  122. /**
  123. * @typedef {object} SymbolBinding
  124. * @property {ConcatenatedModuleInfo} info
  125. * @property {string} name
  126. * @property {string=} comment
  127. * @property {ExportName} ids
  128. * @property {ExportName} exportName
  129. */
  130. /** @typedef {ConcatenatedModuleInfo | ExternalModuleInfo} ModuleInfo */
  131. /** @typedef {ConcatenatedModuleInfo | ExternalModuleInfo | ReferenceToModuleInfo} ModuleInfoOrReference */
  132. /** @typedef {Map<string, string>} ExportMap */
  133. /**
  134. * @typedef {object} ConcatenatedModuleInfo
  135. * @property {"concatenated"} type
  136. * @property {Module} module
  137. * @property {number} index
  138. * @property {Program | undefined} ast
  139. * @property {Source | undefined} internalSource
  140. * @property {ReplaceSource | undefined} source
  141. * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments
  142. * @property {ReadOnlyRuntimeRequirements | undefined} runtimeRequirements
  143. * @property {Scope | undefined} globalScope
  144. * @property {Scope | undefined} moduleScope
  145. * @property {Map<string, string>} internalNames
  146. * @property {ExportMap | undefined} exportMap
  147. * @property {ExportMap | undefined} rawExportMap
  148. * @property {string=} namespaceExportSymbol
  149. * @property {string | undefined} namespaceObjectName
  150. * @property {ConcatenationScope | undefined} concatenationScope
  151. * @property {boolean} interopNamespaceObjectUsed "default-with-named" namespace
  152. * @property {string | undefined} interopNamespaceObjectName "default-with-named" namespace
  153. * @property {boolean} interopNamespaceObject2Used "default-only" namespace
  154. * @property {string | undefined} interopNamespaceObject2Name "default-only" namespace
  155. * @property {boolean} interopDefaultAccessUsed runtime namespace object that detects "__esModule"
  156. * @property {string | undefined} interopDefaultAccessName runtime namespace object that detects "__esModule"
  157. */
  158. /**
  159. * @typedef {object} ExternalModuleInfo
  160. * @property {"external"} type
  161. * @property {Module} module
  162. * @property {RuntimeSpec | boolean} runtimeCondition
  163. * @property {NonDeferAccess} nonDeferAccess
  164. * @property {number} index
  165. * @property {string | undefined} name module.exports / harmony namespace object
  166. * @property {string | undefined} deferredName deferred module.exports / harmony namespace object
  167. * @property {boolean} deferred the module is deferred at least once
  168. * @property {boolean} deferredNamespaceObjectUsed deferred namespace object that being used in a not-analyzable way so it must be materialized
  169. * @property {string | undefined} deferredNamespaceObjectName deferred namespace object that being used in a not-analyzable way so it must be materialized
  170. * @property {boolean} interopNamespaceObjectUsed "default-with-named" namespace
  171. * @property {string | undefined} interopNamespaceObjectName "default-with-named" namespace
  172. * @property {boolean} interopNamespaceObject2Used "default-only" namespace
  173. * @property {string | undefined} interopNamespaceObject2Name "default-only" namespace
  174. * @property {boolean} interopDefaultAccessUsed runtime namespace object that detects "__esModule"
  175. * @property {string | undefined} interopDefaultAccessName runtime namespace object that detects "__esModule"
  176. */
  177. /**
  178. * @typedef {object} ReferenceToModuleInfo
  179. * @property {"reference"} type
  180. * @property {RuntimeSpec | boolean} runtimeCondition
  181. * @property {NonDeferAccess} nonDeferAccess
  182. * @property {ModuleInfo} target
  183. */
  184. /**
  185. * @template T
  186. * @param {string} property property
  187. * @param {(a: T[keyof T], b: T[keyof T]) => 0 | 1 | -1} comparator comparator
  188. * @returns {Comparator<T>} comparator
  189. */
  190. const createComparator = (property, comparator) => (a, b) =>
  191. comparator(
  192. a[/** @type {keyof T} */ (property)],
  193. b[/** @type {keyof T} */ (property)]
  194. );
  195. /**
  196. * @param {number} a a
  197. * @param {number} b b
  198. * @returns {0 | 1 | -1} result
  199. */
  200. const compareNumbers = (a, b) => {
  201. if (Number.isNaN(a)) {
  202. if (!Number.isNaN(b)) {
  203. return 1;
  204. }
  205. } else {
  206. if (Number.isNaN(b)) {
  207. return -1;
  208. }
  209. if (a !== b) {
  210. return a < b ? -1 : 1;
  211. }
  212. }
  213. return 0;
  214. };
  215. const bySourceOrder = createComparator("sourceOrder", compareNumbers);
  216. const byRangeStart = createComparator("rangeStart", compareNumbers);
  217. /**
  218. * @param {Iterable<string>} iterable iterable object
  219. * @returns {string} joined iterable object
  220. */
  221. const joinIterableWithComma = (iterable) => {
  222. // This is more performant than Array.from().join(", ")
  223. // as it doesn't create an array
  224. let str = "";
  225. let first = true;
  226. for (const item of iterable) {
  227. if (first) {
  228. first = false;
  229. } else {
  230. str += ", ";
  231. }
  232. str += item;
  233. }
  234. return str;
  235. };
  236. /** @typedef {boolean} NonDeferAccess */
  237. /**
  238. * @param {NonDeferAccess} a a
  239. * @param {NonDeferAccess} b b
  240. * @returns {NonDeferAccess} merged
  241. */
  242. const mergeNonDeferAccess = (a, b) => a || b;
  243. /**
  244. * @param {NonDeferAccess} a first
  245. * @param {NonDeferAccess} b second
  246. * @returns {NonDeferAccess} first - second
  247. */
  248. const subtractNonDeferAccess = (a, b) => a && !b;
  249. /**
  250. * @typedef {object} ConcatenationEntry
  251. * @property {"concatenated" | "external"} type
  252. * @property {Module} module
  253. * @property {RuntimeSpec | boolean} runtimeCondition
  254. * @property {NonDeferAccess} nonDeferAccess
  255. */
  256. /** @typedef {Set<ConcatenatedModuleInfo>} NeededNamespaceObjects */
  257. /** @typedef {Map<Module, ModuleInfo>} ModuleToInfoMap */
  258. /**
  259. * @param {ModuleGraph} moduleGraph the module graph
  260. * @param {ModuleInfo} info module info
  261. * @param {ExportName} exportName exportName
  262. * @param {ModuleToInfoMap} moduleToInfoMap moduleToInfoMap
  263. * @param {RuntimeSpec} runtime for which runtime
  264. * @param {RequestShortener} requestShortener the request shortener
  265. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  266. * @param {NeededNamespaceObjects} neededNamespaceObjects modules for which a namespace object should be generated
  267. * @param {boolean} asCall asCall
  268. * @param {boolean} depDeferred the dependency is deferred
  269. * @param {boolean | undefined} strictHarmonyModule strictHarmonyModule
  270. * @param {boolean | undefined} asiSafe asiSafe
  271. * @param {Set<ExportInfo>} alreadyVisited alreadyVisited
  272. * @returns {Binding} the final variable
  273. */
  274. const getFinalBinding = (
  275. moduleGraph,
  276. info,
  277. exportName,
  278. moduleToInfoMap,
  279. runtime,
  280. requestShortener,
  281. runtimeTemplate,
  282. neededNamespaceObjects,
  283. asCall,
  284. depDeferred,
  285. strictHarmonyModule,
  286. asiSafe,
  287. alreadyVisited = new Set()
  288. ) => {
  289. const exportsType = info.module.getExportsType(
  290. moduleGraph,
  291. strictHarmonyModule
  292. );
  293. const moduleDeferred =
  294. info.type === "external" &&
  295. info.deferred &&
  296. !(/** @type {BuildMeta} */ (info.module.buildMeta).async);
  297. const deferred = depDeferred && moduleDeferred;
  298. if (exportName.length === 0) {
  299. switch (exportsType) {
  300. case "default-only":
  301. if (deferred) info.deferredNamespaceObjectUsed = true;
  302. else info.interopNamespaceObject2Used = true;
  303. return {
  304. info,
  305. rawName: /** @type {string} */ (
  306. deferred
  307. ? info.deferredNamespaceObjectName
  308. : info.interopNamespaceObject2Name
  309. ),
  310. ids: exportName,
  311. exportName
  312. };
  313. case "default-with-named":
  314. if (deferred) info.deferredNamespaceObjectUsed = true;
  315. else info.interopNamespaceObjectUsed = true;
  316. return {
  317. info,
  318. rawName: /** @type {string} */ (
  319. deferred
  320. ? info.deferredNamespaceObjectName
  321. : info.interopNamespaceObjectName
  322. ),
  323. ids: exportName,
  324. exportName
  325. };
  326. case "namespace":
  327. case "dynamic":
  328. break;
  329. default:
  330. throw new Error(`Unexpected exportsType ${exportsType}`);
  331. }
  332. } else {
  333. switch (exportsType) {
  334. case "namespace":
  335. break;
  336. case "default-with-named":
  337. switch (exportName[0]) {
  338. case "default":
  339. exportName = exportName.slice(1);
  340. break;
  341. case "__esModule":
  342. return {
  343. info,
  344. rawName: "/* __esModule */true",
  345. ids: exportName.slice(1),
  346. exportName
  347. };
  348. }
  349. break;
  350. case "default-only": {
  351. const exportId = exportName[0];
  352. if (exportId === "__esModule") {
  353. return {
  354. info,
  355. rawName: "/* __esModule */true",
  356. ids: exportName.slice(1),
  357. exportName
  358. };
  359. }
  360. exportName = exportName.slice(1);
  361. if (exportId !== "default") {
  362. return {
  363. info,
  364. rawName:
  365. "/* non-default import from default-exporting module */undefined",
  366. ids: exportName,
  367. exportName
  368. };
  369. }
  370. break;
  371. }
  372. case "dynamic":
  373. switch (exportName[0]) {
  374. case "default": {
  375. exportName = exportName.slice(1);
  376. if (deferred) {
  377. return {
  378. info,
  379. rawName: `${info.deferredName}.a`,
  380. ids: exportName,
  381. exportName
  382. };
  383. }
  384. if (moduleDeferred) {
  385. return {
  386. info,
  387. rawName: /** @type {string} */ (info.name),
  388. ids: exportName,
  389. exportName
  390. };
  391. }
  392. info.interopDefaultAccessUsed = true;
  393. const defaultExport = asCall
  394. ? `${info.interopDefaultAccessName}()`
  395. : asiSafe
  396. ? `(${info.interopDefaultAccessName}())`
  397. : asiSafe === false
  398. ? `;(${info.interopDefaultAccessName}())`
  399. : `${info.interopDefaultAccessName}.a`;
  400. return {
  401. info,
  402. rawName: defaultExport,
  403. ids: exportName,
  404. exportName
  405. };
  406. }
  407. case "__esModule":
  408. return {
  409. info,
  410. rawName: "/* __esModule */true",
  411. ids: exportName.slice(1),
  412. exportName
  413. };
  414. }
  415. break;
  416. default:
  417. throw new Error(`Unexpected exportsType ${exportsType}`);
  418. }
  419. }
  420. if (exportName.length === 0) {
  421. switch (info.type) {
  422. case "concatenated":
  423. neededNamespaceObjects.add(info);
  424. return {
  425. info,
  426. rawName:
  427. /** @type {NonNullable<ConcatenatedModuleInfo["namespaceObjectName"]>} */
  428. (info.namespaceObjectName),
  429. ids: exportName,
  430. exportName
  431. };
  432. case "external":
  433. if (deferred) {
  434. info.deferredNamespaceObjectUsed = true;
  435. return {
  436. info,
  437. rawName: /** @type {string} */ (info.deferredNamespaceObjectName),
  438. ids: exportName,
  439. exportName
  440. };
  441. }
  442. return {
  443. info,
  444. rawName:
  445. /** @type {NonNullable<ExternalModuleInfo["name"]>} */
  446. (info.name),
  447. ids: exportName,
  448. exportName
  449. };
  450. }
  451. }
  452. const exportsInfo = moduleGraph.getExportsInfo(info.module);
  453. const exportInfo = exportsInfo.getExportInfo(exportName[0]);
  454. if (alreadyVisited.has(exportInfo)) {
  455. return {
  456. info,
  457. rawName: "/* circular reexport */ Object(function x() { x() }())",
  458. ids: [],
  459. exportName
  460. };
  461. }
  462. alreadyVisited.add(exportInfo);
  463. switch (info.type) {
  464. case "concatenated": {
  465. const exportId = exportName[0];
  466. if (exportInfo.provided === false) {
  467. // It's not provided, but it could be on the prototype
  468. neededNamespaceObjects.add(info);
  469. return {
  470. info,
  471. rawName: /** @type {string} */ (info.namespaceObjectName),
  472. ids: exportName,
  473. exportName
  474. };
  475. }
  476. const directExport = info.exportMap && info.exportMap.get(exportId);
  477. if (directExport) {
  478. const usedName = /** @type {ExportName} */ (
  479. exportsInfo.getUsedName(exportName, runtime)
  480. );
  481. if (!usedName) {
  482. return {
  483. info,
  484. rawName: "/* unused export */ undefined",
  485. ids: exportName.slice(1),
  486. exportName
  487. };
  488. }
  489. return {
  490. info,
  491. name: directExport,
  492. ids: usedName.slice(1),
  493. exportName
  494. };
  495. }
  496. const rawExport = info.rawExportMap && info.rawExportMap.get(exportId);
  497. if (rawExport) {
  498. return {
  499. info,
  500. rawName: rawExport,
  501. ids: exportName.slice(1),
  502. exportName
  503. };
  504. }
  505. const reexport = exportInfo.findTarget(moduleGraph, (module) =>
  506. moduleToInfoMap.has(module)
  507. );
  508. if (reexport === false) {
  509. throw new Error(
  510. `Target module of reexport from '${info.module.readableIdentifier(
  511. requestShortener
  512. )}' is not part of the concatenation (export '${exportId}')\nModules in the concatenation:\n${Array.from(
  513. moduleToInfoMap,
  514. ([m, info]) =>
  515. ` * ${info.type} ${m.readableIdentifier(requestShortener)}`
  516. ).join("\n")}`
  517. );
  518. }
  519. if (reexport) {
  520. const refInfo = moduleToInfoMap.get(reexport.module);
  521. return getFinalBinding(
  522. moduleGraph,
  523. /** @type {ModuleInfo} */ (refInfo),
  524. reexport.export
  525. ? [...reexport.export, ...exportName.slice(1)]
  526. : exportName.slice(1),
  527. moduleToInfoMap,
  528. runtime,
  529. requestShortener,
  530. runtimeTemplate,
  531. neededNamespaceObjects,
  532. asCall,
  533. reexport.deferred,
  534. /** @type {BuildMeta} */
  535. (info.module.buildMeta).strictHarmonyModule,
  536. asiSafe,
  537. alreadyVisited
  538. );
  539. }
  540. if (info.namespaceExportSymbol) {
  541. const usedName = /** @type {ExportName} */ (
  542. exportsInfo.getUsedName(exportName, runtime)
  543. );
  544. return {
  545. info,
  546. rawName: /** @type {string} */ (info.namespaceObjectName),
  547. ids: usedName,
  548. exportName
  549. };
  550. }
  551. throw new Error(
  552. `Cannot get final name for export '${exportName.join(
  553. "."
  554. )}' of ${info.module.readableIdentifier(requestShortener)}`
  555. );
  556. }
  557. case "external": {
  558. const used = /** @type {ExportName} */ (
  559. exportsInfo.getUsedName(exportName, runtime)
  560. );
  561. if (!used) {
  562. return {
  563. info,
  564. rawName: "/* unused export */ undefined",
  565. ids: exportName.slice(1),
  566. exportName
  567. };
  568. }
  569. const comment = equals(used, exportName)
  570. ? ""
  571. : Template.toNormalComment(`${exportName.join(".")}`);
  572. return {
  573. info,
  574. rawName:
  575. (deferred ? info.deferredName : info.name) +
  576. (deferred ? ".a" : "") +
  577. comment,
  578. ids: used,
  579. exportName
  580. };
  581. }
  582. }
  583. };
  584. /**
  585. * @param {ModuleGraph} moduleGraph the module graph
  586. * @param {ModuleInfo} info module info
  587. * @param {ExportName} exportName exportName
  588. * @param {ModuleToInfoMap} moduleToInfoMap moduleToInfoMap
  589. * @param {RuntimeSpec} runtime for which runtime
  590. * @param {RequestShortener} requestShortener the request shortener
  591. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  592. * @param {NeededNamespaceObjects} neededNamespaceObjects modules for which a namespace object should be generated
  593. * @param {boolean} asCall asCall
  594. * @param {boolean} depDeferred the dependency is deferred
  595. * @param {boolean | undefined} callContext callContext
  596. * @param {boolean | undefined} strictHarmonyModule strictHarmonyModule
  597. * @param {boolean | undefined} asiSafe asiSafe
  598. * @returns {string} the final name
  599. */
  600. const getFinalName = (
  601. moduleGraph,
  602. info,
  603. exportName,
  604. moduleToInfoMap,
  605. runtime,
  606. requestShortener,
  607. runtimeTemplate,
  608. neededNamespaceObjects,
  609. asCall,
  610. depDeferred,
  611. callContext,
  612. strictHarmonyModule,
  613. asiSafe
  614. ) => {
  615. const binding = getFinalBinding(
  616. moduleGraph,
  617. info,
  618. exportName,
  619. moduleToInfoMap,
  620. runtime,
  621. requestShortener,
  622. runtimeTemplate,
  623. neededNamespaceObjects,
  624. asCall,
  625. depDeferred,
  626. strictHarmonyModule,
  627. asiSafe
  628. );
  629. {
  630. const { ids, comment } = binding;
  631. /** @type {string} */
  632. let reference;
  633. /** @type {boolean} */
  634. let isPropertyAccess;
  635. if ("rawName" in binding) {
  636. reference = `${binding.rawName}${comment || ""}${propertyAccess(ids)}`;
  637. isPropertyAccess = ids.length > 0;
  638. } else {
  639. const { info, name: exportId } = binding;
  640. const name = info.internalNames.get(exportId);
  641. if (!name) {
  642. throw new Error(
  643. `The export "${exportId}" in "${info.module.readableIdentifier(
  644. requestShortener
  645. )}" has no internal name (existing names: ${
  646. Array.from(
  647. info.internalNames,
  648. ([name, symbol]) => `${name}: ${symbol}`
  649. ).join(", ") || "none"
  650. })`
  651. );
  652. }
  653. reference = `${name}${comment || ""}${propertyAccess(ids)}`;
  654. isPropertyAccess = ids.length > 1;
  655. }
  656. if (isPropertyAccess && asCall && callContext === false) {
  657. return asiSafe
  658. ? `(0,${reference})`
  659. : asiSafe === false
  660. ? `;(0,${reference})`
  661. : `/*#__PURE__*/Object(${reference})`;
  662. }
  663. return reference;
  664. }
  665. };
  666. /**
  667. * @typedef {object} ConcatenateModuleHooks
  668. * @property {SyncBailHook<[ConcatenatedModule, RuntimeSpec[], string, Record<string, string>], boolean>} onDemandExportsGeneration
  669. * @property {SyncBailHook<[Partial<ConcatenatedModuleInfo>, ConcatenatedModuleInfo], boolean | void>} concatenatedModuleInfo
  670. */
  671. /** @typedef {BuildInfo["topLevelDeclarations"]} TopLevelDeclarations */
  672. /** @type {WeakMap<Compilation, ConcatenateModuleHooks>} */
  673. const compilationHooksMap = new WeakMap();
  674. class ConcatenatedModule extends Module {
  675. /**
  676. * @param {Module} rootModule the root module of the concatenation
  677. * @param {Set<Module>} modules all modules in the concatenation (including the root module)
  678. * @param {RuntimeSpec} runtime the runtime
  679. * @param {Compilation} compilation the compilation
  680. * @param {AssociatedObjectForCache=} associatedObjectForCache object for caching
  681. * @param {HashFunction=} hashFunction hash function to use
  682. * @returns {ConcatenatedModule} the module
  683. */
  684. static create(
  685. rootModule,
  686. modules,
  687. runtime,
  688. compilation,
  689. associatedObjectForCache,
  690. hashFunction = DEFAULTS.HASH_FUNCTION
  691. ) {
  692. const identifier = ConcatenatedModule._createIdentifier(
  693. rootModule,
  694. modules,
  695. associatedObjectForCache,
  696. hashFunction
  697. );
  698. return new ConcatenatedModule({
  699. identifier,
  700. rootModule,
  701. modules,
  702. runtime,
  703. compilation
  704. });
  705. }
  706. /**
  707. * @param {Compilation} compilation the compilation
  708. * @returns {ConcatenateModuleHooks} the attached hooks
  709. */
  710. static getCompilationHooks(compilation) {
  711. let hooks = compilationHooksMap.get(compilation);
  712. if (hooks === undefined) {
  713. hooks = {
  714. onDemandExportsGeneration: new SyncBailHook([
  715. "module",
  716. "runtimes",
  717. "exportsFinalName",
  718. "exportsSource"
  719. ]),
  720. concatenatedModuleInfo: new SyncBailHook([
  721. "updatedInfo",
  722. "concatenatedModuleInfo"
  723. ])
  724. };
  725. compilationHooksMap.set(compilation, hooks);
  726. }
  727. return hooks;
  728. }
  729. /**
  730. * @param {object} options options
  731. * @param {string} options.identifier the identifier of the module
  732. * @param {Module} options.rootModule the root module of the concatenation
  733. * @param {RuntimeSpec} options.runtime the selected runtime
  734. * @param {Set<Module>} options.modules all concatenated modules
  735. * @param {Compilation} options.compilation the compilation
  736. */
  737. constructor({ identifier, rootModule, modules, runtime, compilation }) {
  738. super(JAVASCRIPT_MODULE_TYPE_ESM, null, rootModule && rootModule.layer);
  739. // Info from Factory
  740. /** @type {string} */
  741. this._identifier = identifier;
  742. /** @type {Module} */
  743. this.rootModule = rootModule;
  744. /** @type {Set<Module>} */
  745. this._modules = modules;
  746. this._runtime = runtime;
  747. this.factoryMeta = rootModule && rootModule.factoryMeta;
  748. /** @type {Compilation} */
  749. this.compilation = compilation;
  750. }
  751. /**
  752. * Assuming this module is in the cache. Update the (cached) module with
  753. * the fresh module from the factory. Usually updates internal references
  754. * and properties.
  755. * @param {Module} module fresh module
  756. * @returns {void}
  757. */
  758. updateCacheModule(module) {
  759. throw new Error("Must not be called");
  760. }
  761. /**
  762. * @returns {SourceTypes} types available (do not mutate)
  763. */
  764. getSourceTypes() {
  765. return JAVASCRIPT_TYPES;
  766. }
  767. get modules() {
  768. return [...this._modules];
  769. }
  770. /**
  771. * @returns {string} a unique identifier of the module
  772. */
  773. identifier() {
  774. return this._identifier;
  775. }
  776. /**
  777. * @param {RequestShortener} requestShortener the request shortener
  778. * @returns {string} a user readable identifier of the module
  779. */
  780. readableIdentifier(requestShortener) {
  781. return `${this.rootModule.readableIdentifier(
  782. requestShortener
  783. )} + ${this._modules.size - 1} modules`;
  784. }
  785. /**
  786. * @param {LibIdentOptions} options options
  787. * @returns {LibIdent | null} an identifier for library inclusion
  788. */
  789. libIdent(options) {
  790. return this.rootModule.libIdent(options);
  791. }
  792. /**
  793. * @returns {NameForCondition | null} absolute path which should be used for condition matching (usually the resource path)
  794. */
  795. nameForCondition() {
  796. return this.rootModule.nameForCondition();
  797. }
  798. /**
  799. * @param {ModuleGraph} moduleGraph the module graph
  800. * @returns {ConnectionState} how this module should be connected to referencing modules when consumed for side-effects only
  801. */
  802. getSideEffectsConnectionState(moduleGraph) {
  803. return this.rootModule.getSideEffectsConnectionState(moduleGraph);
  804. }
  805. /**
  806. * @param {WebpackOptions} options webpack options
  807. * @param {Compilation} compilation the compilation
  808. * @param {ResolverWithOptions} resolver the resolver
  809. * @param {InputFileSystem} fs the file system
  810. * @param {BuildCallback} callback callback function
  811. * @returns {void}
  812. */
  813. build(options, compilation, resolver, fs, callback) {
  814. const { rootModule } = this;
  815. const { moduleArgument, exportsArgument } =
  816. /** @type {BuildInfo} */
  817. (rootModule.buildInfo);
  818. /** @type {BuildInfo} */
  819. this.buildInfo = {
  820. strict: true,
  821. cacheable: true,
  822. moduleArgument,
  823. exportsArgument,
  824. fileDependencies: new LazySet(),
  825. contextDependencies: new LazySet(),
  826. missingDependencies: new LazySet(),
  827. topLevelDeclarations: new Set(),
  828. assets: undefined
  829. };
  830. this.buildMeta = rootModule.buildMeta;
  831. this.clearDependenciesAndBlocks();
  832. this.clearWarningsAndErrors();
  833. for (const m of this._modules) {
  834. // populate cacheable
  835. if (!(/** @type {BuildInfo} */ (m.buildInfo).cacheable)) {
  836. this.buildInfo.cacheable = false;
  837. }
  838. // populate dependencies
  839. for (const d of m.dependencies.filter(
  840. (dep) =>
  841. !(dep instanceof HarmonyImportDependency) ||
  842. !this._modules.has(
  843. /** @type {Module} */
  844. (compilation.moduleGraph.getModule(dep))
  845. )
  846. )) {
  847. this.dependencies.push(d);
  848. }
  849. // populate blocks
  850. for (const d of m.blocks) {
  851. this.blocks.push(d);
  852. }
  853. // populate warnings
  854. const warnings = m.getWarnings();
  855. if (warnings !== undefined) {
  856. for (const warning of warnings) {
  857. this.addWarning(warning);
  858. }
  859. }
  860. // populate errors
  861. const errors = m.getErrors();
  862. if (errors !== undefined) {
  863. for (const error of errors) {
  864. this.addError(error);
  865. }
  866. }
  867. const { assets, assetsInfo, topLevelDeclarations, needCreateRequire } =
  868. /** @type {BuildInfo} */ (m.buildInfo);
  869. const buildInfo = this.buildInfo;
  870. // populate topLevelDeclarations
  871. if (topLevelDeclarations) {
  872. const topLevelDeclarations = buildInfo.topLevelDeclarations;
  873. if (topLevelDeclarations !== undefined) {
  874. for (const decl of topLevelDeclarations) {
  875. topLevelDeclarations.add(decl);
  876. }
  877. }
  878. } else {
  879. buildInfo.topLevelDeclarations = undefined;
  880. }
  881. // populate needCreateRequire
  882. if (needCreateRequire) {
  883. this.buildInfo.needCreateRequire = true;
  884. }
  885. // populate assets
  886. if (assets) {
  887. if (buildInfo.assets === undefined) {
  888. buildInfo.assets = Object.create(null);
  889. }
  890. Object.assign(
  891. /** @type {NonNullable<BuildInfo["assets"]>} */
  892. (buildInfo.assets),
  893. assets
  894. );
  895. }
  896. if (assetsInfo) {
  897. if (buildInfo.assetsInfo === undefined) {
  898. buildInfo.assetsInfo = new Map();
  899. }
  900. for (const [key, value] of assetsInfo) {
  901. buildInfo.assetsInfo.set(key, value);
  902. }
  903. }
  904. }
  905. callback();
  906. }
  907. /**
  908. * @param {string=} type the source type for which the size should be estimated
  909. * @returns {number} the estimated size of the module (must be non-zero)
  910. */
  911. size(type) {
  912. // Guess size from embedded modules
  913. let size = 0;
  914. for (const module of this._modules) {
  915. size += module.size(type);
  916. }
  917. return size;
  918. }
  919. /**
  920. * @private
  921. * @param {Module} rootModule the root of the concatenation
  922. * @param {Set<Module>} modulesSet a set of modules which should be concatenated
  923. * @param {RuntimeSpec} runtime for this runtime
  924. * @param {ModuleGraph} moduleGraph the module graph
  925. * @returns {ConcatenationEntry[]} concatenation list
  926. */
  927. _createConcatenationList(rootModule, modulesSet, runtime, moduleGraph) {
  928. /** @type {ConcatenationEntry[]} */
  929. const list = [];
  930. /** @type {Map<Module, { runtimeCondition: RuntimeSpec | true, nonDeferAccess: NonDeferAccess }>} */
  931. const existingEntries = new Map();
  932. /**
  933. * @param {Module} module a module
  934. * @returns {Iterable<{ connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true, nonDeferAccess: NonDeferAccess }>} imported modules in order
  935. */
  936. const getConcatenatedImports = (module) => {
  937. const connections = [...moduleGraph.getOutgoingConnections(module)];
  938. if (module === rootModule) {
  939. for (const c of moduleGraph.getOutgoingConnections(this)) {
  940. connections.push(c);
  941. }
  942. }
  943. /**
  944. * @type {{ connection: ModuleGraphConnection, sourceOrder: number, rangeStart: number | undefined, defer?: boolean }[]}
  945. */
  946. const references = connections
  947. .filter((connection) => {
  948. if (!(connection.dependency instanceof HarmonyImportDependency)) {
  949. return false;
  950. }
  951. if (!connection.module.getSourceBasicTypes().has(JAVASCRIPT_TYPE)) {
  952. return false;
  953. }
  954. return (
  955. connection &&
  956. connection.resolvedOriginModule === module &&
  957. connection.module &&
  958. connection.isTargetActive(runtime)
  959. );
  960. })
  961. .map((connection) => {
  962. const dep =
  963. /** @type {HarmonyImportDependency} */
  964. (connection.dependency);
  965. return {
  966. connection,
  967. sourceOrder: /** @type {number} */ (dep.sourceOrder),
  968. rangeStart: dep.range && dep.range[0],
  969. defer: ImportPhaseUtils.isDefer(dep.phase)
  970. };
  971. });
  972. /**
  973. * bySourceOrder
  974. * @example
  975. * import a from "a"; // sourceOrder=1
  976. * import b from "b"; // sourceOrder=2
  977. *
  978. * byRangeStart
  979. * @example
  980. * import {a, b} from "a"; // sourceOrder=1
  981. * a.a(); // first range
  982. * b.b(); // second range
  983. *
  984. * If there is no reexport, we have the same source.
  985. * If there is reexport, but module has side effects, this will lead to reexport module only.
  986. * If there is side-effects-free reexport, we can get simple deterministic result with range start comparison.
  987. */
  988. references.sort(concatComparators(bySourceOrder, byRangeStart));
  989. /** @type {Map<Module, { connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true, nonDeferAccess: NonDeferAccess }>} */
  990. const referencesMap = new Map();
  991. for (const { connection, defer } of references) {
  992. const runtimeCondition = filterRuntime(runtime, (r) =>
  993. connection.isTargetActive(r)
  994. );
  995. if (runtimeCondition === false) continue;
  996. const nonDeferAccess = !defer;
  997. const module = connection.module;
  998. const entry = referencesMap.get(module);
  999. if (entry === undefined) {
  1000. referencesMap.set(module, {
  1001. connection,
  1002. runtimeCondition,
  1003. nonDeferAccess
  1004. });
  1005. continue;
  1006. }
  1007. entry.runtimeCondition = mergeRuntimeConditionNonFalse(
  1008. entry.runtimeCondition,
  1009. runtimeCondition,
  1010. runtime
  1011. );
  1012. entry.nonDeferAccess = mergeNonDeferAccess(
  1013. entry.nonDeferAccess,
  1014. nonDeferAccess
  1015. );
  1016. }
  1017. return referencesMap.values();
  1018. };
  1019. /**
  1020. * @param {ModuleGraphConnection} connection graph connection
  1021. * @param {RuntimeSpec | true} runtimeCondition runtime condition
  1022. * @param {NonDeferAccess} nonDeferAccess non-defer access
  1023. * @returns {void}
  1024. */
  1025. const enterModule = (connection, runtimeCondition, nonDeferAccess) => {
  1026. const module = connection.module;
  1027. if (!module) return;
  1028. const existingEntry = existingEntries.get(module);
  1029. if (
  1030. existingEntry &&
  1031. existingEntry.runtimeCondition === true &&
  1032. existingEntry.nonDeferAccess === true
  1033. ) {
  1034. return;
  1035. }
  1036. if (modulesSet.has(module)) {
  1037. existingEntries.set(module, {
  1038. runtimeCondition: true,
  1039. nonDeferAccess: true
  1040. });
  1041. if (runtimeCondition !== true) {
  1042. throw new Error(
  1043. `Cannot runtime-conditional concatenate a module (${module.identifier()} in ${this.rootModule.identifier()}, ${runtimeConditionToString(
  1044. runtimeCondition
  1045. )}). This should not happen.`
  1046. );
  1047. }
  1048. if (nonDeferAccess !== true) {
  1049. throw new Error(
  1050. `Cannot deferred concatenate a module (${module.identifier()} in ${this.rootModule.identifier()}. This should not happen.`
  1051. );
  1052. }
  1053. const imports = getConcatenatedImports(module);
  1054. for (const {
  1055. connection,
  1056. runtimeCondition,
  1057. nonDeferAccess
  1058. } of imports) {
  1059. enterModule(connection, runtimeCondition, nonDeferAccess);
  1060. }
  1061. list.push({
  1062. type: "concatenated",
  1063. module: connection.module,
  1064. runtimeCondition,
  1065. nonDeferAccess
  1066. });
  1067. } else {
  1068. /** @type {RuntimeSpec | boolean} */
  1069. let reducedRuntimeCondition;
  1070. /** @type {NonDeferAccess} */
  1071. let reducedNonDeferAccess;
  1072. if (existingEntry !== undefined) {
  1073. reducedRuntimeCondition = subtractRuntimeCondition(
  1074. runtimeCondition,
  1075. existingEntry.runtimeCondition,
  1076. runtime
  1077. );
  1078. reducedNonDeferAccess = subtractNonDeferAccess(
  1079. nonDeferAccess,
  1080. existingEntry.nonDeferAccess
  1081. );
  1082. if (
  1083. reducedRuntimeCondition === false &&
  1084. reducedNonDeferAccess === false
  1085. ) {
  1086. return;
  1087. }
  1088. if (reducedRuntimeCondition !== false) {
  1089. existingEntry.runtimeCondition = mergeRuntimeConditionNonFalse(
  1090. existingEntry.runtimeCondition,
  1091. reducedRuntimeCondition,
  1092. runtime
  1093. );
  1094. }
  1095. if (reducedNonDeferAccess !== false) {
  1096. existingEntry.nonDeferAccess = mergeNonDeferAccess(
  1097. existingEntry.nonDeferAccess,
  1098. reducedNonDeferAccess
  1099. );
  1100. }
  1101. } else {
  1102. reducedRuntimeCondition = runtimeCondition;
  1103. reducedNonDeferAccess = nonDeferAccess;
  1104. existingEntries.set(connection.module, {
  1105. runtimeCondition,
  1106. nonDeferAccess
  1107. });
  1108. }
  1109. if (list.length > 0) {
  1110. const lastItem = list[list.length - 1];
  1111. if (
  1112. lastItem.type === "external" &&
  1113. lastItem.module === connection.module
  1114. ) {
  1115. lastItem.runtimeCondition = mergeRuntimeCondition(
  1116. lastItem.runtimeCondition,
  1117. reducedRuntimeCondition,
  1118. runtime
  1119. );
  1120. lastItem.nonDeferAccess = mergeNonDeferAccess(
  1121. lastItem.nonDeferAccess,
  1122. reducedNonDeferAccess
  1123. );
  1124. return;
  1125. }
  1126. }
  1127. list.push({
  1128. type: "external",
  1129. get module() {
  1130. // We need to use a getter here, because the module in the dependency
  1131. // could be replaced by some other process (i. e. also replaced with a
  1132. // concatenated module)
  1133. return connection.module;
  1134. },
  1135. runtimeCondition: reducedRuntimeCondition,
  1136. nonDeferAccess: reducedNonDeferAccess
  1137. });
  1138. }
  1139. };
  1140. existingEntries.set(rootModule, {
  1141. runtimeCondition: true,
  1142. nonDeferAccess: true
  1143. });
  1144. const imports = getConcatenatedImports(rootModule);
  1145. for (const { connection, runtimeCondition, nonDeferAccess } of imports) {
  1146. enterModule(connection, runtimeCondition, nonDeferAccess);
  1147. }
  1148. list.push({
  1149. type: "concatenated",
  1150. module: rootModule,
  1151. runtimeCondition: true,
  1152. nonDeferAccess: true
  1153. });
  1154. return list;
  1155. }
  1156. /**
  1157. * @param {Module} rootModule the root module of the concatenation
  1158. * @param {Set<Module>} modules all modules in the concatenation (including the root module)
  1159. * @param {AssociatedObjectForCache=} associatedObjectForCache object for caching
  1160. * @param {HashFunction=} hashFunction hash function to use
  1161. * @returns {string} the identifier
  1162. */
  1163. static _createIdentifier(
  1164. rootModule,
  1165. modules,
  1166. associatedObjectForCache,
  1167. hashFunction = DEFAULTS.HASH_FUNCTION
  1168. ) {
  1169. const cachedMakePathsRelative = makePathsRelative.bindContextCache(
  1170. /** @type {string} */ (rootModule.context),
  1171. associatedObjectForCache
  1172. );
  1173. /** @type {string[]} */
  1174. const identifiers = [];
  1175. for (const module of modules) {
  1176. identifiers.push(cachedMakePathsRelative(module.identifier()));
  1177. }
  1178. identifiers.sort();
  1179. const hash = createHash(hashFunction);
  1180. hash.update(identifiers.join(" "));
  1181. return `${rootModule.identifier()}|${hash.digest("hex")}`;
  1182. }
  1183. /**
  1184. * @param {FileSystemDependencies} fileDependencies set where file dependencies are added to
  1185. * @param {FileSystemDependencies} contextDependencies set where context dependencies are added to
  1186. * @param {FileSystemDependencies} missingDependencies set where missing dependencies are added to
  1187. * @param {FileSystemDependencies} buildDependencies set where build dependencies are added to
  1188. */
  1189. addCacheDependencies(
  1190. fileDependencies,
  1191. contextDependencies,
  1192. missingDependencies,
  1193. buildDependencies
  1194. ) {
  1195. for (const module of this._modules) {
  1196. module.addCacheDependencies(
  1197. fileDependencies,
  1198. contextDependencies,
  1199. missingDependencies,
  1200. buildDependencies
  1201. );
  1202. }
  1203. }
  1204. /**
  1205. * @param {CodeGenerationContext} context context for code generation
  1206. * @returns {CodeGenerationResult} result
  1207. */
  1208. codeGeneration({
  1209. dependencyTemplates,
  1210. runtimeTemplate,
  1211. moduleGraph,
  1212. chunkGraph,
  1213. runtime: generationRuntime,
  1214. runtimes,
  1215. codeGenerationResults
  1216. }) {
  1217. const { concatenatedModuleInfo } = ConcatenatedModule.getCompilationHooks(
  1218. this.compilation
  1219. );
  1220. /** @type {RuntimeRequirements} */
  1221. const runtimeRequirements = new Set();
  1222. const runtime = intersectRuntime(generationRuntime, this._runtime);
  1223. const requestShortener = runtimeTemplate.requestShortener;
  1224. // Meta info for each module
  1225. const [modulesWithInfo, moduleToInfoMap] = this._getModulesWithInfo(
  1226. moduleGraph,
  1227. runtime
  1228. );
  1229. // Set with modules that need a generated namespace object
  1230. /** @type {NeededNamespaceObjects} */
  1231. const neededNamespaceObjects = new Set();
  1232. // List of all used names to avoid conflicts
  1233. const allUsedNames = new Set(RESERVED_NAMES);
  1234. // Generate source code and analyse scopes
  1235. // Prepare a ReplaceSource for the final source
  1236. for (const info of moduleToInfoMap.values()) {
  1237. this._analyseModule(
  1238. moduleToInfoMap,
  1239. info,
  1240. dependencyTemplates,
  1241. runtimeTemplate,
  1242. moduleGraph,
  1243. chunkGraph,
  1244. runtime,
  1245. runtimes,
  1246. /** @type {CodeGenerationResults} */
  1247. (codeGenerationResults),
  1248. allUsedNames
  1249. );
  1250. }
  1251. // Updated Top level declarations are created by renaming
  1252. /** @type {TopLevelDeclarations} */
  1253. const topLevelDeclarations = new Set();
  1254. // List of additional names in scope for module references
  1255. /** @type {Map<string, ScopeInfo>} */
  1256. const usedNamesInScopeInfo = new Map();
  1257. // Set of already checked scopes
  1258. /** @type {Set<Scope>} */
  1259. const ignoredScopes = new Set();
  1260. // get all global names
  1261. for (const info of modulesWithInfo) {
  1262. if (info.type === "concatenated") {
  1263. // ignore symbols from moduleScope
  1264. if (info.moduleScope) {
  1265. ignoredScopes.add(info.moduleScope);
  1266. }
  1267. // The super class expression in class scopes behaves weird
  1268. // We get ranges of all super class expressions to make
  1269. // renaming to work correctly
  1270. /** @typedef {{ range: Range, variables: Variable[] }} ClassInfo */
  1271. /** @type {WeakMap<Scope, ClassInfo[]>} */
  1272. const superClassCache = new WeakMap();
  1273. /**
  1274. * @param {Scope} scope scope
  1275. * @returns {ClassInfo[]} result
  1276. */
  1277. const getSuperClassExpressions = (scope) => {
  1278. const cacheEntry = superClassCache.get(scope);
  1279. if (cacheEntry !== undefined) return cacheEntry;
  1280. /** @type {ClassInfo[]} */
  1281. const superClassExpressions = [];
  1282. for (const childScope of scope.childScopes) {
  1283. if (childScope.type !== "class") continue;
  1284. const block = childScope.block;
  1285. if (
  1286. (block.type === "ClassDeclaration" ||
  1287. block.type === "ClassExpression") &&
  1288. block.superClass
  1289. ) {
  1290. superClassExpressions.push({
  1291. range: /** @type {Range} */ (block.superClass.range),
  1292. variables: childScope.variables
  1293. });
  1294. }
  1295. }
  1296. superClassCache.set(scope, superClassExpressions);
  1297. return superClassExpressions;
  1298. };
  1299. // add global symbols
  1300. if (info.globalScope) {
  1301. for (const reference of info.globalScope.through) {
  1302. const name = reference.identifier.name;
  1303. if (ConcatenationScope.isModuleReference(name)) {
  1304. const match = ConcatenationScope.matchModuleReference(name);
  1305. if (!match) continue;
  1306. const referencedInfo = modulesWithInfo[match.index];
  1307. if (referencedInfo.type === "reference") {
  1308. throw new Error("Module reference can't point to a reference");
  1309. }
  1310. const binding = getFinalBinding(
  1311. moduleGraph,
  1312. referencedInfo,
  1313. match.ids,
  1314. moduleToInfoMap,
  1315. runtime,
  1316. requestShortener,
  1317. runtimeTemplate,
  1318. neededNamespaceObjects,
  1319. false,
  1320. match.deferredImport,
  1321. /** @type {BuildMeta} */
  1322. (info.module.buildMeta).strictHarmonyModule,
  1323. true
  1324. );
  1325. if (!binding.ids) continue;
  1326. const { usedNames, alreadyCheckedScopes } =
  1327. getUsedNamesInScopeInfo(
  1328. usedNamesInScopeInfo,
  1329. binding.info.module.identifier(),
  1330. "name" in binding ? binding.name : ""
  1331. );
  1332. for (const expr of getSuperClassExpressions(reference.from)) {
  1333. if (
  1334. expr.range[0] <=
  1335. /** @type {Range} */ (reference.identifier.range)[0] &&
  1336. expr.range[1] >=
  1337. /** @type {Range} */ (reference.identifier.range)[1]
  1338. ) {
  1339. for (const variable of expr.variables) {
  1340. usedNames.add(variable.name);
  1341. }
  1342. }
  1343. }
  1344. addScopeSymbols(
  1345. reference.from,
  1346. usedNames,
  1347. alreadyCheckedScopes,
  1348. ignoredScopes
  1349. );
  1350. } else {
  1351. allUsedNames.add(name);
  1352. }
  1353. }
  1354. }
  1355. }
  1356. }
  1357. /**
  1358. * @param {string} name the name to find a new name for
  1359. * @param {ConcatenatedModuleInfo} info the info of the module
  1360. * @param {Reference[]} references the references to the name
  1361. * @returns {string | undefined} the new name or undefined if the name is not found
  1362. */
  1363. const _findNewName = (name, info, references) => {
  1364. const { usedNames, alreadyCheckedScopes } = getUsedNamesInScopeInfo(
  1365. usedNamesInScopeInfo,
  1366. info.module.identifier(),
  1367. name
  1368. );
  1369. if (allUsedNames.has(name) || usedNames.has(name)) {
  1370. for (const ref of references) {
  1371. addScopeSymbols(
  1372. ref.from,
  1373. usedNames,
  1374. alreadyCheckedScopes,
  1375. ignoredScopes
  1376. );
  1377. }
  1378. const newName = findNewName(
  1379. name,
  1380. allUsedNames,
  1381. usedNames,
  1382. info.module.readableIdentifier(requestShortener)
  1383. );
  1384. allUsedNames.add(newName);
  1385. info.internalNames.set(name, newName);
  1386. topLevelDeclarations.add(newName);
  1387. return newName;
  1388. }
  1389. };
  1390. /**
  1391. * @param {string} name the name to find a new name for
  1392. * @param {ConcatenatedModuleInfo} info the info of the module
  1393. * @param {Reference[]} references the references to the name
  1394. * @returns {string | undefined} the new name or undefined if the name is not found
  1395. */
  1396. const _findNewNameForSpecifier = (name, info, references) => {
  1397. const { usedNames: moduleUsedNames, alreadyCheckedScopes } =
  1398. getUsedNamesInScopeInfo(
  1399. usedNamesInScopeInfo,
  1400. info.module.identifier(),
  1401. name
  1402. );
  1403. /** @type {UsedNames} */
  1404. const referencesUsedNames = new Set();
  1405. for (const ref of references) {
  1406. addScopeSymbols(
  1407. ref.from,
  1408. referencesUsedNames,
  1409. alreadyCheckedScopes,
  1410. ignoredScopes
  1411. );
  1412. }
  1413. if (moduleUsedNames.has(name) || referencesUsedNames.has(name)) {
  1414. const newName = findNewName(
  1415. name,
  1416. allUsedNames,
  1417. new Set([...moduleUsedNames, ...referencesUsedNames]),
  1418. info.module.readableIdentifier(requestShortener)
  1419. );
  1420. allUsedNames.add(newName);
  1421. topLevelDeclarations.add(newName);
  1422. return newName;
  1423. }
  1424. };
  1425. // generate names for symbols
  1426. for (const info of moduleToInfoMap.values()) {
  1427. const { usedNames: namespaceObjectUsedNames } = getUsedNamesInScopeInfo(
  1428. usedNamesInScopeInfo,
  1429. info.module.identifier(),
  1430. ""
  1431. );
  1432. switch (info.type) {
  1433. case "concatenated": {
  1434. const variables = /** @type {Scope} */ (info.moduleScope).variables;
  1435. for (const variable of variables) {
  1436. const name = variable.name;
  1437. const references = getAllReferences(variable);
  1438. const newName = _findNewName(name, info, references);
  1439. if (newName) {
  1440. const source = /** @type {ReplaceSource} */ (info.source);
  1441. const allIdentifiers = new Set([
  1442. ...references.map((r) => r.identifier),
  1443. ...variable.identifiers
  1444. ]);
  1445. for (const identifier of allIdentifiers) {
  1446. const r = /** @type {Range} */ (identifier.range);
  1447. const path = getPathInAst(
  1448. /** @type {NonNullable<ConcatenatedModuleInfo["ast"]>} */
  1449. (info.ast),
  1450. identifier
  1451. );
  1452. if (path && path.length > 1) {
  1453. const maybeProperty =
  1454. path[1].type === "AssignmentPattern" &&
  1455. path[1].left === path[0]
  1456. ? path[2]
  1457. : path[1];
  1458. if (
  1459. maybeProperty.type === "Property" &&
  1460. maybeProperty.shorthand
  1461. ) {
  1462. source.insert(r[1], `: ${newName}`);
  1463. continue;
  1464. }
  1465. }
  1466. source.replace(r[0], r[1] - 1, newName);
  1467. }
  1468. } else {
  1469. allUsedNames.add(name);
  1470. info.internalNames.set(name, name);
  1471. topLevelDeclarations.add(name);
  1472. }
  1473. }
  1474. /** @type {string} */
  1475. let namespaceObjectName;
  1476. if (info.namespaceExportSymbol) {
  1477. namespaceObjectName =
  1478. /** @type {string} */
  1479. (info.internalNames.get(info.namespaceExportSymbol));
  1480. } else {
  1481. namespaceObjectName = findNewName(
  1482. "namespaceObject",
  1483. allUsedNames,
  1484. namespaceObjectUsedNames,
  1485. info.module.readableIdentifier(requestShortener)
  1486. );
  1487. allUsedNames.add(namespaceObjectName);
  1488. }
  1489. info.namespaceObjectName = namespaceObjectName;
  1490. topLevelDeclarations.add(namespaceObjectName);
  1491. break;
  1492. }
  1493. case "external": {
  1494. const externalName = findNewName(
  1495. "",
  1496. allUsedNames,
  1497. namespaceObjectUsedNames,
  1498. info.module.readableIdentifier(requestShortener)
  1499. );
  1500. allUsedNames.add(externalName);
  1501. info.name = externalName;
  1502. topLevelDeclarations.add(externalName);
  1503. if (info.deferred) {
  1504. const externalName = findNewName(
  1505. "deferred",
  1506. allUsedNames,
  1507. namespaceObjectUsedNames,
  1508. info.module.readableIdentifier(requestShortener)
  1509. );
  1510. allUsedNames.add(externalName);
  1511. info.deferredName = externalName;
  1512. topLevelDeclarations.add(externalName);
  1513. const externalNameInterop = findNewName(
  1514. "deferredNamespaceObject",
  1515. allUsedNames,
  1516. namespaceObjectUsedNames,
  1517. info.module.readableIdentifier(requestShortener)
  1518. );
  1519. allUsedNames.add(externalNameInterop);
  1520. info.deferredNamespaceObjectName = externalNameInterop;
  1521. topLevelDeclarations.add(externalNameInterop);
  1522. }
  1523. break;
  1524. }
  1525. }
  1526. const buildMeta = /** @type {BuildMeta} */ (info.module.buildMeta);
  1527. if (buildMeta.exportsType !== "namespace") {
  1528. const externalNameInterop = findNewName(
  1529. "namespaceObject",
  1530. allUsedNames,
  1531. namespaceObjectUsedNames,
  1532. info.module.readableIdentifier(requestShortener)
  1533. );
  1534. allUsedNames.add(externalNameInterop);
  1535. info.interopNamespaceObjectName = externalNameInterop;
  1536. topLevelDeclarations.add(externalNameInterop);
  1537. }
  1538. if (
  1539. buildMeta.exportsType === "default" &&
  1540. buildMeta.defaultObject !== "redirect" &&
  1541. info.interopNamespaceObject2Used
  1542. ) {
  1543. const externalNameInterop = findNewName(
  1544. "namespaceObject2",
  1545. allUsedNames,
  1546. namespaceObjectUsedNames,
  1547. info.module.readableIdentifier(requestShortener)
  1548. );
  1549. allUsedNames.add(externalNameInterop);
  1550. info.interopNamespaceObject2Name = externalNameInterop;
  1551. topLevelDeclarations.add(externalNameInterop);
  1552. }
  1553. if (buildMeta.exportsType === "dynamic" || !buildMeta.exportsType) {
  1554. const externalNameInterop = findNewName(
  1555. "default",
  1556. allUsedNames,
  1557. namespaceObjectUsedNames,
  1558. info.module.readableIdentifier(requestShortener)
  1559. );
  1560. allUsedNames.add(externalNameInterop);
  1561. info.interopDefaultAccessName = externalNameInterop;
  1562. topLevelDeclarations.add(externalNameInterop);
  1563. }
  1564. }
  1565. // Find and replace references to modules
  1566. for (const info of moduleToInfoMap.values()) {
  1567. if (info.type === "concatenated") {
  1568. const globalScope = /** @type {Scope} */ (info.globalScope);
  1569. // group references by name
  1570. /** @type {Map<string, Reference[]>} */
  1571. const referencesByName = new Map();
  1572. for (const reference of globalScope.through) {
  1573. const name = reference.identifier.name;
  1574. if (!referencesByName.has(name)) {
  1575. referencesByName.set(name, []);
  1576. }
  1577. /** @type {Reference[]} */
  1578. (referencesByName.get(name)).push(reference);
  1579. }
  1580. for (const [name, references] of referencesByName) {
  1581. const match = ConcatenationScope.matchModuleReference(name);
  1582. if (match) {
  1583. const referencedInfo = modulesWithInfo[match.index];
  1584. if (referencedInfo.type === "reference") {
  1585. throw new Error("Module reference can't point to a reference");
  1586. }
  1587. const concatenationScope = /** @type {ConcatenatedModuleInfo} */ (
  1588. referencedInfo
  1589. ).concatenationScope;
  1590. const exportId = match.ids[0];
  1591. const specifier =
  1592. concatenationScope && concatenationScope.getRawExport(exportId);
  1593. if (specifier) {
  1594. const newName = _findNewNameForSpecifier(
  1595. specifier,
  1596. info,
  1597. references
  1598. );
  1599. const initFragmentChanged =
  1600. newName &&
  1601. concatenatedModuleInfo.call(
  1602. {
  1603. rawExportMap: new Map([
  1604. [exportId, /** @type {string} */ (newName)]
  1605. ])
  1606. },
  1607. /** @type {ConcatenatedModuleInfo} */ (referencedInfo)
  1608. );
  1609. if (initFragmentChanged) {
  1610. concatenationScope.setRawExportMap(exportId, newName);
  1611. }
  1612. }
  1613. const finalName = getFinalName(
  1614. moduleGraph,
  1615. referencedInfo,
  1616. match.ids,
  1617. moduleToInfoMap,
  1618. runtime,
  1619. requestShortener,
  1620. runtimeTemplate,
  1621. neededNamespaceObjects,
  1622. match.call,
  1623. match.deferredImport,
  1624. !match.directImport,
  1625. /** @type {BuildMeta} */
  1626. (info.module.buildMeta).strictHarmonyModule,
  1627. match.asiSafe
  1628. );
  1629. for (const reference of references) {
  1630. const r = /** @type {Range} */ (reference.identifier.range);
  1631. const source = /** @type {ReplaceSource} */ (info.source);
  1632. // range is extended by 2 chars to cover the appended "._"
  1633. source.replace(r[0], r[1] + 1, finalName);
  1634. }
  1635. }
  1636. }
  1637. }
  1638. }
  1639. // Map with all root exposed used exports
  1640. /** @type {Map<string, (requestShortener: RequestShortener) => string>} */
  1641. const exportsMap = new Map();
  1642. // Set with all root exposed unused exports
  1643. /** @type {Set<string>} */
  1644. const unusedExports = new Set();
  1645. const rootInfo =
  1646. /** @type {ConcatenatedModuleInfo} */
  1647. (moduleToInfoMap.get(this.rootModule));
  1648. const strictHarmonyModule =
  1649. /** @type {BuildMeta} */
  1650. (rootInfo.module.buildMeta).strictHarmonyModule;
  1651. const exportsInfo = moduleGraph.getExportsInfo(rootInfo.module);
  1652. /** @type {Record<string, string>} */
  1653. const exportsFinalName = {};
  1654. for (const exportInfo of exportsInfo.orderedExports) {
  1655. const name = exportInfo.name;
  1656. if (exportInfo.provided === false) continue;
  1657. const used = exportInfo.getUsedName(undefined, runtime);
  1658. if (!used) {
  1659. unusedExports.add(name);
  1660. continue;
  1661. }
  1662. exportsMap.set(used, (requestShortener) => {
  1663. try {
  1664. const finalName = getFinalName(
  1665. moduleGraph,
  1666. rootInfo,
  1667. [name],
  1668. moduleToInfoMap,
  1669. runtime,
  1670. requestShortener,
  1671. runtimeTemplate,
  1672. neededNamespaceObjects,
  1673. false,
  1674. false,
  1675. false,
  1676. strictHarmonyModule,
  1677. true
  1678. );
  1679. exportsFinalName[used] = finalName;
  1680. return `/* ${
  1681. exportInfo.isReexport() ? "reexport" : "binding"
  1682. } */ ${finalName}`;
  1683. } catch (err) {
  1684. /** @type {Error} */
  1685. (err).message +=
  1686. `\nwhile generating the root export '${name}' (used name: '${used}')`;
  1687. throw err;
  1688. }
  1689. });
  1690. }
  1691. const result = new ConcatSource();
  1692. // add harmony compatibility flag (must be first because of possible circular dependencies)
  1693. let shouldAddHarmonyFlag = false;
  1694. const rootExportsInfo = moduleGraph.getExportsInfo(this);
  1695. if (
  1696. rootExportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused ||
  1697. rootExportsInfo.getReadOnlyExportInfo("__esModule").getUsed(runtime) !==
  1698. UsageState.Unused
  1699. ) {
  1700. shouldAddHarmonyFlag = true;
  1701. }
  1702. // define exports
  1703. if (exportsMap.size > 0) {
  1704. /** @type {string[]} */
  1705. const definitions = [];
  1706. for (const [key, value] of exportsMap) {
  1707. definitions.push(
  1708. `\n ${propertyName(key)}: ${runtimeTemplate.returningFunction(
  1709. value(requestShortener)
  1710. )}`
  1711. );
  1712. }
  1713. runtimeRequirements.add(RuntimeGlobals.exports);
  1714. runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
  1715. if (shouldAddHarmonyFlag) {
  1716. result.add("// ESM COMPAT FLAG\n");
  1717. result.add(
  1718. runtimeTemplate.defineEsModuleFlagStatement({
  1719. exportsArgument: this.exportsArgument,
  1720. runtimeRequirements
  1721. })
  1722. );
  1723. }
  1724. const exportsSource =
  1725. "\n// EXPORTS\n" +
  1726. `${RuntimeGlobals.definePropertyGetters}(${this.exportsArgument}, {${definitions.join(
  1727. ","
  1728. )}\n});\n`;
  1729. const { onDemandExportsGeneration } =
  1730. ConcatenatedModule.getCompilationHooks(this.compilation);
  1731. if (
  1732. !onDemandExportsGeneration.call(
  1733. this,
  1734. runtimes,
  1735. exportsSource,
  1736. exportsFinalName
  1737. )
  1738. ) {
  1739. result.add(exportsSource);
  1740. }
  1741. }
  1742. // list unused exports
  1743. if (unusedExports.size > 0) {
  1744. result.add(
  1745. `\n// UNUSED EXPORTS: ${joinIterableWithComma(unusedExports)}\n`
  1746. );
  1747. }
  1748. // generate namespace objects
  1749. /** @type {Map<ConcatenatedModuleInfo, string>} */
  1750. const namespaceObjectSources = new Map();
  1751. for (const info of neededNamespaceObjects) {
  1752. if (info.namespaceExportSymbol) continue;
  1753. /** @type {string[]} */
  1754. const nsObj = [];
  1755. const exportsInfo = moduleGraph.getExportsInfo(info.module);
  1756. for (const exportInfo of exportsInfo.orderedExports) {
  1757. if (exportInfo.provided === false) continue;
  1758. const usedName = exportInfo.getUsedName(undefined, runtime);
  1759. if (usedName) {
  1760. const finalName = getFinalName(
  1761. moduleGraph,
  1762. info,
  1763. [exportInfo.name],
  1764. moduleToInfoMap,
  1765. runtime,
  1766. requestShortener,
  1767. runtimeTemplate,
  1768. neededNamespaceObjects,
  1769. false,
  1770. false,
  1771. undefined,
  1772. /** @type {BuildMeta} */
  1773. (info.module.buildMeta).strictHarmonyModule,
  1774. true
  1775. );
  1776. nsObj.push(
  1777. `\n ${propertyName(usedName)}: ${runtimeTemplate.returningFunction(
  1778. finalName
  1779. )}`
  1780. );
  1781. }
  1782. }
  1783. const name = info.namespaceObjectName;
  1784. const defineGetters =
  1785. nsObj.length > 0
  1786. ? `${RuntimeGlobals.definePropertyGetters}(${name}, {${nsObj.join(
  1787. ","
  1788. )}\n});\n`
  1789. : "";
  1790. if (nsObj.length > 0) {
  1791. runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
  1792. }
  1793. namespaceObjectSources.set(
  1794. info,
  1795. `
  1796. // NAMESPACE OBJECT: ${info.module.readableIdentifier(requestShortener)}
  1797. var ${name} = {};
  1798. ${RuntimeGlobals.makeNamespaceObject}(${name});
  1799. ${defineGetters}`
  1800. );
  1801. runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
  1802. }
  1803. // define required namespace objects (must be before evaluation modules)
  1804. for (const info of modulesWithInfo) {
  1805. if (info.type === "concatenated") {
  1806. const source = namespaceObjectSources.get(info);
  1807. if (!source) continue;
  1808. result.add(source);
  1809. }
  1810. if (info.type === "external" && info.deferred) {
  1811. const moduleId = JSON.stringify(chunkGraph.getModuleId(info.module));
  1812. const loader = getOptimizedDeferredModule(
  1813. moduleId,
  1814. info.module.getExportsType(
  1815. moduleGraph,
  1816. /** @type {BuildMeta} */
  1817. (this.rootModule.buildMeta).strictHarmonyModule
  1818. ),
  1819. // an async module will opt-out of the concat module optimization.
  1820. [],
  1821. runtimeRequirements
  1822. );
  1823. runtimeRequirements.add(RuntimeGlobals.require);
  1824. result.add(
  1825. `\n// DEFERRED EXTERNAL MODULE: ${info.module.readableIdentifier(requestShortener)}\nvar ${info.deferredName} = ${loader};`
  1826. );
  1827. if (info.deferredNamespaceObjectUsed) {
  1828. runtimeRequirements.add(RuntimeGlobals.makeDeferredNamespaceObject);
  1829. result.add(
  1830. `\nvar ${info.deferredNamespaceObjectName} = /*#__PURE__*/${
  1831. RuntimeGlobals.makeDeferredNamespaceObject
  1832. }(${JSON.stringify(
  1833. chunkGraph.getModuleId(info.module)
  1834. )}, ${getMakeDeferredNamespaceModeFromExportsType(
  1835. info.module.getExportsType(moduleGraph, strictHarmonyModule)
  1836. )});`
  1837. );
  1838. }
  1839. }
  1840. }
  1841. /** @type {InitFragment<ChunkRenderContext>[]} */
  1842. const chunkInitFragments = [];
  1843. // evaluate modules in order
  1844. for (const rawInfo of modulesWithInfo) {
  1845. /** @type {undefined | string} */
  1846. let name;
  1847. let isConditional = false;
  1848. const info = rawInfo.type === "reference" ? rawInfo.target : rawInfo;
  1849. switch (info.type) {
  1850. case "concatenated": {
  1851. result.add(
  1852. `\n;// ${info.module.readableIdentifier(requestShortener)}\n`
  1853. );
  1854. result.add(/** @type {ReplaceSource} */ (info.source));
  1855. if (info.chunkInitFragments) {
  1856. for (const f of info.chunkInitFragments) chunkInitFragments.push(f);
  1857. }
  1858. if (info.runtimeRequirements) {
  1859. for (const r of info.runtimeRequirements) {
  1860. runtimeRequirements.add(r);
  1861. }
  1862. }
  1863. name = info.namespaceObjectName;
  1864. break;
  1865. }
  1866. case "external": {
  1867. // deferred case is handled in the "const info of modulesWithInfo" loop above
  1868. if (!info.deferred) {
  1869. result.add(
  1870. `\n// EXTERNAL MODULE: ${info.module.readableIdentifier(
  1871. requestShortener
  1872. )}\n`
  1873. );
  1874. runtimeRequirements.add(RuntimeGlobals.require);
  1875. const { runtimeCondition } =
  1876. /** @type {ExternalModuleInfo | ReferenceToModuleInfo} */
  1877. (rawInfo);
  1878. const condition = runtimeTemplate.runtimeConditionExpression({
  1879. chunkGraph,
  1880. runtimeCondition,
  1881. runtime,
  1882. runtimeRequirements
  1883. });
  1884. if (condition !== "true") {
  1885. isConditional = true;
  1886. result.add(`if (${condition}) {\n`);
  1887. }
  1888. const moduleId = JSON.stringify(
  1889. chunkGraph.getModuleId(info.module)
  1890. );
  1891. result.add(`var ${info.name} = __webpack_require__(${moduleId});`);
  1892. name = info.name;
  1893. }
  1894. // If a module is deferred in other places, but used as non-deferred here,
  1895. // the module itself will be emitted as mod_deferred (in the case "external"),
  1896. // we need to emit an extra import declaration to evaluate it in order.
  1897. const { nonDeferAccess } =
  1898. /** @type {ExternalModuleInfo | ReferenceToModuleInfo} */
  1899. (rawInfo);
  1900. if (info.deferred && nonDeferAccess) {
  1901. result.add(
  1902. `\n// non-deferred import to a deferred module (${info.module.readableIdentifier(requestShortener)})\nvar ${info.name} = ${info.deferredName}.a;`
  1903. );
  1904. }
  1905. break;
  1906. }
  1907. default:
  1908. // @ts-expect-error never is expected here
  1909. throw new Error(`Unsupported concatenation entry type ${info.type}`);
  1910. }
  1911. if (info.interopNamespaceObjectUsed) {
  1912. runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
  1913. result.add(
  1914. `\nvar ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name}, 2);`
  1915. );
  1916. }
  1917. if (info.interopNamespaceObject2Used) {
  1918. runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
  1919. result.add(
  1920. `\nvar ${info.interopNamespaceObject2Name} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name});`
  1921. );
  1922. }
  1923. if (info.interopDefaultAccessUsed) {
  1924. runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
  1925. result.add(
  1926. `\nvar ${info.interopDefaultAccessName} = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${name});`
  1927. );
  1928. }
  1929. if (isConditional) {
  1930. result.add("\n}");
  1931. }
  1932. }
  1933. /** @type {CodeGenerationResultData} */
  1934. const data = new Map();
  1935. if (chunkInitFragments.length > 0) {
  1936. data.set("chunkInitFragments", chunkInitFragments);
  1937. }
  1938. data.set("topLevelDeclarations", topLevelDeclarations);
  1939. /** @type {CodeGenerationResult} */
  1940. const resultEntry = {
  1941. sources: new Map([[JAVASCRIPT_TYPE, new CachedSource(result)]]),
  1942. data,
  1943. runtimeRequirements
  1944. };
  1945. return resultEntry;
  1946. }
  1947. /**
  1948. * @param {ModuleToInfoMap} modulesMap modulesMap
  1949. * @param {ModuleInfo} info info
  1950. * @param {DependencyTemplates} dependencyTemplates dependencyTemplates
  1951. * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate
  1952. * @param {ModuleGraph} moduleGraph moduleGraph
  1953. * @param {ChunkGraph} chunkGraph chunkGraph
  1954. * @param {RuntimeSpec} runtime runtime
  1955. * @param {RuntimeSpec[]} runtimes runtimes
  1956. * @param {CodeGenerationResults} codeGenerationResults codeGenerationResults
  1957. * @param {UsedNames} usedNames used names
  1958. */
  1959. _analyseModule(
  1960. modulesMap,
  1961. info,
  1962. dependencyTemplates,
  1963. runtimeTemplate,
  1964. moduleGraph,
  1965. chunkGraph,
  1966. runtime,
  1967. runtimes,
  1968. codeGenerationResults,
  1969. usedNames
  1970. ) {
  1971. if (info.type === "concatenated") {
  1972. const m = info.module;
  1973. try {
  1974. // Create a concatenation scope to track and capture information
  1975. const concatenationScope = new ConcatenationScope(
  1976. modulesMap,
  1977. info,
  1978. usedNames
  1979. );
  1980. // TODO cache codeGeneration results
  1981. const codeGenResult = m.codeGeneration({
  1982. dependencyTemplates,
  1983. runtimeTemplate,
  1984. moduleGraph,
  1985. chunkGraph,
  1986. runtime,
  1987. runtimes,
  1988. concatenationScope,
  1989. codeGenerationResults,
  1990. sourceTypes: JAVASCRIPT_TYPES
  1991. });
  1992. const source =
  1993. /** @type {Source} */
  1994. (codeGenResult.sources.get(JAVASCRIPT_TYPE));
  1995. const data = codeGenResult.data;
  1996. const chunkInitFragments = data && data.get("chunkInitFragments");
  1997. const code = source.source().toString();
  1998. /** @type {Program} */
  1999. let ast;
  2000. try {
  2001. ({ ast } = JavascriptParser._parse(
  2002. code,
  2003. {
  2004. sourceType: "module",
  2005. ranges: true
  2006. },
  2007. JavascriptParser._getModuleParseFunction(this.compilation, m)
  2008. ));
  2009. } catch (_err) {
  2010. const err =
  2011. /** @type {Error & { loc?: { line: number, column: number } }} */
  2012. (_err);
  2013. if (
  2014. err.loc &&
  2015. typeof err.loc === "object" &&
  2016. typeof err.loc.line === "number"
  2017. ) {
  2018. const lineNumber = err.loc.line;
  2019. const lines = code.split("\n");
  2020. err.message += `\n| ${lines
  2021. .slice(Math.max(0, lineNumber - 3), lineNumber + 2)
  2022. .join("\n| ")}`;
  2023. }
  2024. throw err;
  2025. }
  2026. const scopeManager = eslintScope.analyze(ast, {
  2027. ecmaVersion: 6,
  2028. sourceType: "module",
  2029. optimistic: true,
  2030. ignoreEval: true,
  2031. impliedStrict: true
  2032. });
  2033. const globalScope = /** @type {Scope} */ (scopeManager.acquire(ast));
  2034. const moduleScope = globalScope.childScopes[0];
  2035. const resultSource = new ReplaceSource(source);
  2036. info.runtimeRequirements =
  2037. /** @type {ReadOnlyRuntimeRequirements} */
  2038. (codeGenResult.runtimeRequirements);
  2039. info.ast = ast;
  2040. info.internalSource = source;
  2041. info.source = resultSource;
  2042. info.chunkInitFragments = chunkInitFragments;
  2043. info.globalScope = globalScope;
  2044. info.moduleScope = moduleScope;
  2045. info.concatenationScope = concatenationScope;
  2046. } catch (err) {
  2047. /** @type {Error} */
  2048. (err).message +=
  2049. `\nwhile analyzing module ${m.identifier()} for concatenation`;
  2050. throw err;
  2051. }
  2052. }
  2053. }
  2054. /**
  2055. * @param {ModuleGraph} moduleGraph the module graph
  2056. * @param {RuntimeSpec} runtime the runtime
  2057. * @returns {[ModuleInfoOrReference[], ModuleToInfoMap]} module info items
  2058. */
  2059. _getModulesWithInfo(moduleGraph, runtime) {
  2060. const orderedConcatenationList = this._createConcatenationList(
  2061. this.rootModule,
  2062. this._modules,
  2063. runtime,
  2064. moduleGraph
  2065. );
  2066. /** @type {ModuleToInfoMap} */
  2067. const map = new Map();
  2068. const list = orderedConcatenationList.map((info, index) => {
  2069. let item = map.get(info.module);
  2070. if (item === undefined) {
  2071. switch (info.type) {
  2072. case "concatenated":
  2073. item = {
  2074. type: "concatenated",
  2075. module: info.module,
  2076. index,
  2077. ast: undefined,
  2078. internalSource: undefined,
  2079. runtimeRequirements: undefined,
  2080. source: undefined,
  2081. globalScope: undefined,
  2082. moduleScope: undefined,
  2083. internalNames: new Map(),
  2084. exportMap: undefined,
  2085. rawExportMap: undefined,
  2086. namespaceExportSymbol: undefined,
  2087. namespaceObjectName: undefined,
  2088. interopNamespaceObjectUsed: false,
  2089. interopNamespaceObjectName: undefined,
  2090. interopNamespaceObject2Used: false,
  2091. interopNamespaceObject2Name: undefined,
  2092. interopDefaultAccessUsed: false,
  2093. interopDefaultAccessName: undefined,
  2094. concatenationScope: undefined
  2095. };
  2096. break;
  2097. case "external":
  2098. item = {
  2099. type: "external",
  2100. module: info.module,
  2101. runtimeCondition: info.runtimeCondition,
  2102. nonDeferAccess: info.nonDeferAccess,
  2103. index,
  2104. name: undefined,
  2105. deferredName: undefined,
  2106. interopNamespaceObjectUsed: false,
  2107. interopNamespaceObjectName: undefined,
  2108. interopNamespaceObject2Used: false,
  2109. interopNamespaceObject2Name: undefined,
  2110. interopDefaultAccessUsed: false,
  2111. interopDefaultAccessName: undefined,
  2112. deferred: moduleGraph.isDeferred(info.module),
  2113. deferredNamespaceObjectName: undefined,
  2114. deferredNamespaceObjectUsed: false
  2115. };
  2116. break;
  2117. default:
  2118. throw new Error(
  2119. `Unsupported concatenation entry type ${info.type}`
  2120. );
  2121. }
  2122. map.set(
  2123. /** @type {ModuleInfo} */ (item).module,
  2124. /** @type {ModuleInfo} */ (item)
  2125. );
  2126. return /** @type {ModuleInfo} */ (item);
  2127. }
  2128. /** @type {ReferenceToModuleInfo} */
  2129. const ref = {
  2130. type: "reference",
  2131. runtimeCondition: info.runtimeCondition,
  2132. nonDeferAccess: info.nonDeferAccess,
  2133. target: item
  2134. };
  2135. return ref;
  2136. });
  2137. return [list, map];
  2138. }
  2139. /**
  2140. * @param {Hash} hash the hash used to track dependencies
  2141. * @param {UpdateHashContext} context context
  2142. * @returns {void}
  2143. */
  2144. updateHash(hash, context) {
  2145. const { chunkGraph, runtime } = context;
  2146. for (const info of this._createConcatenationList(
  2147. this.rootModule,
  2148. this._modules,
  2149. intersectRuntime(runtime, this._runtime),
  2150. chunkGraph.moduleGraph
  2151. )) {
  2152. switch (info.type) {
  2153. case "concatenated":
  2154. info.module.updateHash(hash, context);
  2155. break;
  2156. case "external":
  2157. hash.update(`${chunkGraph.getModuleId(info.module)}`);
  2158. // TODO runtimeCondition
  2159. break;
  2160. }
  2161. }
  2162. super.updateHash(hash, context);
  2163. }
  2164. /**
  2165. * @param {ObjectDeserializerContext} context context
  2166. * @returns {ConcatenatedModule} ConcatenatedModule
  2167. */
  2168. static deserialize(context) {
  2169. const obj = new ConcatenatedModule({
  2170. identifier: /** @type {EXPECTED_ANY} */ (undefined),
  2171. rootModule: /** @type {EXPECTED_ANY} */ (undefined),
  2172. modules: /** @type {EXPECTED_ANY} */ (undefined),
  2173. runtime: undefined,
  2174. compilation: /** @type {EXPECTED_ANY} */ (undefined)
  2175. });
  2176. obj.deserialize(context);
  2177. return obj;
  2178. }
  2179. }
  2180. makeSerializable(ConcatenatedModule, "webpack/lib/optimize/ConcatenatedModule");
  2181. module.exports = ConcatenatedModule;