ConcatenatedModule.js 55 KB

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