ConcatenatedModule.js 65 KB

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