ConcatenatedModule.js 55 KB

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