ConcatenatedModule.js 61 KB

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