ConcatenatedModule.js 55 KB

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