JavascriptModulesPlugin.js 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651
  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 { SyncWaterfallHook, SyncHook, SyncBailHook } = require("tapable");
  8. const vm = require("vm");
  9. const {
  10. ConcatSource,
  11. OriginalSource,
  12. PrefixSource,
  13. RawSource,
  14. CachedSource,
  15. ReplaceSource
  16. } = require("webpack-sources");
  17. const Compilation = require("../Compilation");
  18. const { tryRunOrWebpackError } = require("../HookWebpackError");
  19. const HotUpdateChunk = require("../HotUpdateChunk");
  20. const InitFragment = require("../InitFragment");
  21. const {
  22. JAVASCRIPT_MODULE_TYPE_AUTO,
  23. JAVASCRIPT_MODULE_TYPE_DYNAMIC,
  24. JAVASCRIPT_MODULE_TYPE_ESM,
  25. WEBPACK_MODULE_TYPE_RUNTIME
  26. } = require("../ModuleTypeConstants");
  27. const RuntimeGlobals = require("../RuntimeGlobals");
  28. const Template = require("../Template");
  29. const { last, someInIterable } = require("../util/IterableHelpers");
  30. const StringXor = require("../util/StringXor");
  31. const { compareModulesByIdentifier } = require("../util/comparators");
  32. const {
  33. getPathInAst,
  34. getAllReferences,
  35. RESERVED_NAMES,
  36. findNewName,
  37. addScopeSymbols,
  38. getUsedNamesInScopeInfo
  39. } = require("../util/concatenate");
  40. const createHash = require("../util/createHash");
  41. const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
  42. const { intersectRuntime } = require("../util/runtime");
  43. const JavascriptGenerator = require("./JavascriptGenerator");
  44. const JavascriptParser = require("./JavascriptParser");
  45. /** @typedef {import("eslint-scope").Reference} Reference */
  46. /** @typedef {import("eslint-scope").Scope} Scope */
  47. /** @typedef {import("eslint-scope").Variable} Variable */
  48. /** @typedef {import("webpack-sources").Source} Source */
  49. /** @typedef {import("../../declarations/WebpackOptions").Output} OutputOptions */
  50. /** @typedef {import("../Chunk")} Chunk */
  51. /** @typedef {import("../ChunkGraph")} ChunkGraph */
  52. /** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
  53. /** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
  54. /** @typedef {import("../Compilation").ModuleObject} ModuleObject */
  55. /** @typedef {import("../Compiler")} Compiler */
  56. /** @typedef {import("../DependencyTemplates")} DependencyTemplates */
  57. /** @typedef {import("../Entrypoint")} Entrypoint */
  58. /** @typedef {import("../Module")} Module */
  59. /** @typedef {import("../Module").BuildInfo} BuildInfo */
  60. /** @typedef {import("../ModuleGraph")} ModuleGraph */
  61. /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
  62. /** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
  63. /** @typedef {import("../WebpackError")} WebpackError */
  64. /** @typedef {import("../javascript/JavascriptParser").Range} Range */
  65. /** @typedef {import("../util/Hash")} Hash */
  66. /** @typedef {import("../util/createHash").Algorithm} Algorithm */
  67. /**
  68. * @param {Chunk} chunk a chunk
  69. * @param {ChunkGraph} chunkGraph the chunk graph
  70. * @returns {boolean} true, when a JS file is needed for this chunk
  71. */
  72. const chunkHasJs = (chunk, chunkGraph) => {
  73. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) return true;
  74. return Boolean(
  75. chunkGraph.getChunkModulesIterableBySourceType(chunk, "javascript")
  76. );
  77. };
  78. /**
  79. * @param {Chunk} chunk a chunk
  80. * @param {ChunkGraph} chunkGraph the chunk graph
  81. * @returns {boolean} true, when a JS file is needed for this chunk
  82. */
  83. const chunkHasRuntimeOrJs = (chunk, chunkGraph) => {
  84. if (
  85. chunkGraph.getChunkModulesIterableBySourceType(
  86. chunk,
  87. WEBPACK_MODULE_TYPE_RUNTIME
  88. )
  89. )
  90. return true;
  91. return Boolean(
  92. chunkGraph.getChunkModulesIterableBySourceType(chunk, "javascript")
  93. );
  94. };
  95. /**
  96. * @param {Module} module a module
  97. * @param {string} code the code
  98. * @returns {string} generated code for the stack
  99. */
  100. const printGeneratedCodeForStack = (module, code) => {
  101. const lines = code.split("\n");
  102. const n = `${lines.length}`.length;
  103. return `\n\nGenerated code for ${module.identifier()}\n${lines
  104. .map(
  105. /**
  106. * @param {string} line the line
  107. * @param {number} i the index
  108. * @param {string[]} lines the lines
  109. * @returns {string} the line with line number
  110. */
  111. (line, i, lines) => {
  112. const iStr = `${i + 1}`;
  113. return `${" ".repeat(n - iStr.length)}${iStr} | ${line}`;
  114. }
  115. )
  116. .join("\n")}`;
  117. };
  118. /**
  119. * @typedef {object} RenderContext
  120. * @property {Chunk} chunk the chunk
  121. * @property {DependencyTemplates} dependencyTemplates the dependency templates
  122. * @property {RuntimeTemplate} runtimeTemplate the runtime template
  123. * @property {ModuleGraph} moduleGraph the module graph
  124. * @property {ChunkGraph} chunkGraph the chunk graph
  125. * @property {CodeGenerationResults} codeGenerationResults results of code generation
  126. * @property {boolean | undefined} strictMode rendering in strict context
  127. */
  128. /**
  129. * @typedef {object} MainRenderContext
  130. * @property {Chunk} chunk the chunk
  131. * @property {DependencyTemplates} dependencyTemplates the dependency templates
  132. * @property {RuntimeTemplate} runtimeTemplate the runtime template
  133. * @property {ModuleGraph} moduleGraph the module graph
  134. * @property {ChunkGraph} chunkGraph the chunk graph
  135. * @property {CodeGenerationResults} codeGenerationResults results of code generation
  136. * @property {string} hash hash to be used for render call
  137. * @property {boolean | undefined} strictMode rendering in strict context
  138. */
  139. /**
  140. * @typedef {object} ChunkRenderContext
  141. * @property {Chunk} chunk the chunk
  142. * @property {DependencyTemplates} dependencyTemplates the dependency templates
  143. * @property {RuntimeTemplate} runtimeTemplate the runtime template
  144. * @property {ModuleGraph} moduleGraph the module graph
  145. * @property {ChunkGraph} chunkGraph the chunk graph
  146. * @property {CodeGenerationResults} codeGenerationResults results of code generation
  147. * @property {InitFragment<ChunkRenderContext>[]} chunkInitFragments init fragments for the chunk
  148. * @property {boolean | undefined} strictMode rendering in strict context
  149. */
  150. /**
  151. * @typedef {object} RenderBootstrapContext
  152. * @property {Chunk} chunk the chunk
  153. * @property {CodeGenerationResults} codeGenerationResults results of code generation
  154. * @property {RuntimeTemplate} runtimeTemplate the runtime template
  155. * @property {ModuleGraph} moduleGraph the module graph
  156. * @property {ChunkGraph} chunkGraph the chunk graph
  157. * @property {string} hash hash to be used for render call
  158. */
  159. /** @typedef {RenderContext & { inlined: boolean }} StartupRenderContext */
  160. /**
  161. * @typedef {object} CompilationHooks
  162. * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModuleContent
  163. * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModuleContainer
  164. * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModulePackage
  165. * @property {SyncWaterfallHook<[Source, RenderContext]>} renderChunk
  166. * @property {SyncWaterfallHook<[Source, RenderContext]>} renderMain
  167. * @property {SyncWaterfallHook<[Source, RenderContext]>} renderContent
  168. * @property {SyncWaterfallHook<[Source, RenderContext]>} render
  169. * @property {SyncWaterfallHook<[Source, Module, StartupRenderContext]>} renderStartup
  170. * @property {SyncWaterfallHook<[string, RenderBootstrapContext]>} renderRequire
  171. * @property {SyncBailHook<[Module, RenderBootstrapContext], string | void>} inlineInRuntimeBailout
  172. * @property {SyncBailHook<[Module, RenderContext], string | void>} embedInRuntimeBailout
  173. * @property {SyncBailHook<[RenderContext], string | void>} strictRuntimeBailout
  174. * @property {SyncHook<[Chunk, Hash, ChunkHashContext]>} chunkHash
  175. * @property {SyncBailHook<[Chunk, RenderContext], boolean | void>} useSourceMap
  176. */
  177. /** @type {WeakMap<Compilation, CompilationHooks>} */
  178. const compilationHooksMap = new WeakMap();
  179. const PLUGIN_NAME = "JavascriptModulesPlugin";
  180. /** @typedef {{ header: string[], beforeStartup: string[], startup: string[], afterStartup: string[], allowInlineStartup: boolean }} Bootstrap */
  181. class JavascriptModulesPlugin {
  182. /**
  183. * @param {Compilation} compilation the compilation
  184. * @returns {CompilationHooks} the attached hooks
  185. */
  186. static getCompilationHooks(compilation) {
  187. if (!(compilation instanceof Compilation)) {
  188. throw new TypeError(
  189. "The 'compilation' argument must be an instance of Compilation"
  190. );
  191. }
  192. let hooks = compilationHooksMap.get(compilation);
  193. if (hooks === undefined) {
  194. hooks = {
  195. renderModuleContent: new SyncWaterfallHook([
  196. "source",
  197. "module",
  198. "renderContext"
  199. ]),
  200. renderModuleContainer: new SyncWaterfallHook([
  201. "source",
  202. "module",
  203. "renderContext"
  204. ]),
  205. renderModulePackage: new SyncWaterfallHook([
  206. "source",
  207. "module",
  208. "renderContext"
  209. ]),
  210. render: new SyncWaterfallHook(["source", "renderContext"]),
  211. renderContent: new SyncWaterfallHook(["source", "renderContext"]),
  212. renderStartup: new SyncWaterfallHook([
  213. "source",
  214. "module",
  215. "startupRenderContext"
  216. ]),
  217. renderChunk: new SyncWaterfallHook(["source", "renderContext"]),
  218. renderMain: new SyncWaterfallHook(["source", "renderContext"]),
  219. renderRequire: new SyncWaterfallHook(["code", "renderContext"]),
  220. inlineInRuntimeBailout: new SyncBailHook(["module", "renderContext"]),
  221. embedInRuntimeBailout: new SyncBailHook(["module", "renderContext"]),
  222. strictRuntimeBailout: new SyncBailHook(["renderContext"]),
  223. chunkHash: new SyncHook(["chunk", "hash", "context"]),
  224. useSourceMap: new SyncBailHook(["chunk", "renderContext"])
  225. };
  226. compilationHooksMap.set(compilation, hooks);
  227. }
  228. return hooks;
  229. }
  230. constructor(options = {}) {
  231. this.options = options;
  232. /** @type {WeakMap<Source, TODO>} */
  233. this._moduleFactoryCache = new WeakMap();
  234. }
  235. /**
  236. * Apply the plugin
  237. * @param {Compiler} compiler the compiler instance
  238. * @returns {void}
  239. */
  240. apply(compiler) {
  241. compiler.hooks.compilation.tap(
  242. PLUGIN_NAME,
  243. (compilation, { normalModuleFactory }) => {
  244. const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
  245. normalModuleFactory.hooks.createParser
  246. .for(JAVASCRIPT_MODULE_TYPE_AUTO)
  247. .tap(PLUGIN_NAME, options => new JavascriptParser("auto"));
  248. normalModuleFactory.hooks.createParser
  249. .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC)
  250. .tap(PLUGIN_NAME, options => new JavascriptParser("script"));
  251. normalModuleFactory.hooks.createParser
  252. .for(JAVASCRIPT_MODULE_TYPE_ESM)
  253. .tap(PLUGIN_NAME, options => new JavascriptParser("module"));
  254. normalModuleFactory.hooks.createGenerator
  255. .for(JAVASCRIPT_MODULE_TYPE_AUTO)
  256. .tap(PLUGIN_NAME, () => new JavascriptGenerator());
  257. normalModuleFactory.hooks.createGenerator
  258. .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC)
  259. .tap(PLUGIN_NAME, () => new JavascriptGenerator());
  260. normalModuleFactory.hooks.createGenerator
  261. .for(JAVASCRIPT_MODULE_TYPE_ESM)
  262. .tap(PLUGIN_NAME, () => new JavascriptGenerator());
  263. compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
  264. const {
  265. hash,
  266. chunk,
  267. chunkGraph,
  268. moduleGraph,
  269. runtimeTemplate,
  270. dependencyTemplates,
  271. outputOptions,
  272. codeGenerationResults
  273. } = options;
  274. const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
  275. const filenameTemplate =
  276. JavascriptModulesPlugin.getChunkFilenameTemplate(
  277. chunk,
  278. outputOptions
  279. );
  280. let render;
  281. if (hotUpdateChunk) {
  282. render = () =>
  283. this.renderChunk(
  284. {
  285. chunk,
  286. dependencyTemplates,
  287. runtimeTemplate,
  288. moduleGraph,
  289. chunkGraph,
  290. codeGenerationResults,
  291. strictMode: runtimeTemplate.isModule()
  292. },
  293. hooks
  294. );
  295. } else if (chunk.hasRuntime()) {
  296. if (!chunkHasRuntimeOrJs(chunk, chunkGraph)) {
  297. return result;
  298. }
  299. render = () =>
  300. this.renderMain(
  301. {
  302. hash,
  303. chunk,
  304. dependencyTemplates,
  305. runtimeTemplate,
  306. moduleGraph,
  307. chunkGraph,
  308. codeGenerationResults,
  309. strictMode: runtimeTemplate.isModule()
  310. },
  311. hooks,
  312. compilation
  313. );
  314. } else {
  315. if (!chunkHasJs(chunk, chunkGraph)) {
  316. return result;
  317. }
  318. render = () =>
  319. this.renderChunk(
  320. {
  321. chunk,
  322. dependencyTemplates,
  323. runtimeTemplate,
  324. moduleGraph,
  325. chunkGraph,
  326. codeGenerationResults,
  327. strictMode: runtimeTemplate.isModule()
  328. },
  329. hooks
  330. );
  331. }
  332. result.push({
  333. render,
  334. filenameTemplate,
  335. pathOptions: {
  336. hash,
  337. runtime: chunk.runtime,
  338. chunk,
  339. contentHashType: "javascript"
  340. },
  341. info: {
  342. javascriptModule: compilation.runtimeTemplate.isModule()
  343. },
  344. identifier: hotUpdateChunk
  345. ? `hotupdatechunk${chunk.id}`
  346. : `chunk${chunk.id}`,
  347. hash: chunk.contentHash.javascript
  348. });
  349. return result;
  350. });
  351. compilation.hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, context) => {
  352. hooks.chunkHash.call(chunk, hash, context);
  353. if (chunk.hasRuntime()) {
  354. this.updateHashWithBootstrap(
  355. hash,
  356. {
  357. hash: "0000",
  358. chunk,
  359. codeGenerationResults: context.codeGenerationResults,
  360. chunkGraph: context.chunkGraph,
  361. moduleGraph: context.moduleGraph,
  362. runtimeTemplate: context.runtimeTemplate
  363. },
  364. hooks
  365. );
  366. }
  367. });
  368. compilation.hooks.contentHash.tap(PLUGIN_NAME, chunk => {
  369. const {
  370. chunkGraph,
  371. codeGenerationResults,
  372. moduleGraph,
  373. runtimeTemplate,
  374. outputOptions: {
  375. hashSalt,
  376. hashDigest,
  377. hashDigestLength,
  378. hashFunction
  379. }
  380. } = compilation;
  381. const hash = createHash(/** @type {Algorithm} */ (hashFunction));
  382. if (hashSalt) hash.update(hashSalt);
  383. if (chunk.hasRuntime()) {
  384. this.updateHashWithBootstrap(
  385. hash,
  386. {
  387. hash: "0000",
  388. chunk,
  389. codeGenerationResults,
  390. chunkGraph: compilation.chunkGraph,
  391. moduleGraph: compilation.moduleGraph,
  392. runtimeTemplate: compilation.runtimeTemplate
  393. },
  394. hooks
  395. );
  396. } else {
  397. hash.update(`${chunk.id} `);
  398. hash.update(chunk.ids ? chunk.ids.join(",") : "");
  399. }
  400. hooks.chunkHash.call(chunk, hash, {
  401. chunkGraph,
  402. codeGenerationResults,
  403. moduleGraph,
  404. runtimeTemplate
  405. });
  406. const modules = chunkGraph.getChunkModulesIterableBySourceType(
  407. chunk,
  408. "javascript"
  409. );
  410. if (modules) {
  411. const xor = new StringXor();
  412. for (const m of modules) {
  413. xor.add(chunkGraph.getModuleHash(m, chunk.runtime));
  414. }
  415. xor.updateHash(hash);
  416. }
  417. const runtimeModules = chunkGraph.getChunkModulesIterableBySourceType(
  418. chunk,
  419. WEBPACK_MODULE_TYPE_RUNTIME
  420. );
  421. if (runtimeModules) {
  422. const xor = new StringXor();
  423. for (const m of runtimeModules) {
  424. xor.add(chunkGraph.getModuleHash(m, chunk.runtime));
  425. }
  426. xor.updateHash(hash);
  427. }
  428. const digest = /** @type {string} */ (hash.digest(hashDigest));
  429. chunk.contentHash.javascript = nonNumericOnlyHash(
  430. digest,
  431. /** @type {number} */
  432. (hashDigestLength)
  433. );
  434. });
  435. compilation.hooks.additionalTreeRuntimeRequirements.tap(
  436. PLUGIN_NAME,
  437. (chunk, set, { chunkGraph }) => {
  438. if (
  439. !set.has(RuntimeGlobals.startupNoDefault) &&
  440. chunkGraph.hasChunkEntryDependentChunks(chunk)
  441. ) {
  442. set.add(RuntimeGlobals.onChunksLoaded);
  443. set.add(RuntimeGlobals.exports);
  444. set.add(RuntimeGlobals.require);
  445. }
  446. }
  447. );
  448. compilation.hooks.executeModule.tap(PLUGIN_NAME, (options, context) => {
  449. const source = options.codeGenerationResult.sources.get("javascript");
  450. if (source === undefined) return;
  451. const { module } = options;
  452. const code = source.source();
  453. const fn = vm.runInThisContext(
  454. `(function(${module.moduleArgument}, ${module.exportsArgument}, ${RuntimeGlobals.require}) {\n${code}\n/**/})`,
  455. {
  456. filename: module.identifier(),
  457. lineOffset: -1
  458. }
  459. );
  460. const moduleObject =
  461. /** @type {ModuleObject} */
  462. (options.moduleObject);
  463. try {
  464. fn.call(
  465. moduleObject.exports,
  466. moduleObject,
  467. moduleObject.exports,
  468. context.__webpack_require__
  469. );
  470. } catch (err) {
  471. /** @type {Error} */
  472. (err).stack += printGeneratedCodeForStack(
  473. options.module,
  474. /** @type {string} */ (code)
  475. );
  476. throw err;
  477. }
  478. });
  479. compilation.hooks.executeModule.tap(PLUGIN_NAME, (options, context) => {
  480. const source = options.codeGenerationResult.sources.get("runtime");
  481. if (source === undefined) return;
  482. let code = source.source();
  483. if (typeof code !== "string") code = code.toString();
  484. const fn = vm.runInThisContext(
  485. `(function(${RuntimeGlobals.require}) {\n${code}\n/**/})`,
  486. {
  487. filename: options.module.identifier(),
  488. lineOffset: -1
  489. }
  490. );
  491. try {
  492. // eslint-disable-next-line no-useless-call
  493. fn.call(null, context.__webpack_require__);
  494. } catch (err) {
  495. /** @type {Error} */
  496. (err).stack += printGeneratedCodeForStack(options.module, code);
  497. throw err;
  498. }
  499. });
  500. }
  501. );
  502. }
  503. /**
  504. * @param {Chunk} chunk chunk
  505. * @param {OutputOptions} outputOptions output options
  506. * @returns {TemplatePath} used filename template
  507. */
  508. static getChunkFilenameTemplate(chunk, outputOptions) {
  509. if (chunk.filenameTemplate) {
  510. return chunk.filenameTemplate;
  511. } else if (chunk instanceof HotUpdateChunk) {
  512. return /** @type {TemplatePath} */ (outputOptions.hotUpdateChunkFilename);
  513. } else if (chunk.canBeInitial()) {
  514. return /** @type {TemplatePath} */ (outputOptions.filename);
  515. }
  516. return /** @type {TemplatePath} */ (outputOptions.chunkFilename);
  517. }
  518. /**
  519. * @param {Module} module the rendered module
  520. * @param {ChunkRenderContext} renderContext options object
  521. * @param {CompilationHooks} hooks hooks
  522. * @param {boolean} factory true: renders as factory method, false: pure module content
  523. * @returns {Source | null} the newly generated source from rendering
  524. */
  525. renderModule(module, renderContext, hooks, factory) {
  526. const {
  527. chunk,
  528. chunkGraph,
  529. runtimeTemplate,
  530. codeGenerationResults,
  531. strictMode
  532. } = renderContext;
  533. try {
  534. const codeGenResult = codeGenerationResults.get(module, chunk.runtime);
  535. const moduleSource = codeGenResult.sources.get("javascript");
  536. if (!moduleSource) return null;
  537. if (codeGenResult.data !== undefined) {
  538. const chunkInitFragments = codeGenResult.data.get("chunkInitFragments");
  539. if (chunkInitFragments) {
  540. for (const i of chunkInitFragments)
  541. renderContext.chunkInitFragments.push(i);
  542. }
  543. }
  544. const moduleSourcePostContent = tryRunOrWebpackError(
  545. () =>
  546. hooks.renderModuleContent.call(moduleSource, module, renderContext),
  547. "JavascriptModulesPlugin.getCompilationHooks().renderModuleContent"
  548. );
  549. let moduleSourcePostContainer;
  550. if (factory) {
  551. const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
  552. module,
  553. chunk.runtime
  554. );
  555. const needModule = runtimeRequirements.has(RuntimeGlobals.module);
  556. const needExports = runtimeRequirements.has(RuntimeGlobals.exports);
  557. const needRequire =
  558. runtimeRequirements.has(RuntimeGlobals.require) ||
  559. runtimeRequirements.has(RuntimeGlobals.requireScope);
  560. const needThisAsExports = runtimeRequirements.has(
  561. RuntimeGlobals.thisAsExports
  562. );
  563. const needStrict =
  564. /** @type {BuildInfo} */
  565. (module.buildInfo).strict && !strictMode;
  566. const cacheEntry = this._moduleFactoryCache.get(
  567. moduleSourcePostContent
  568. );
  569. let source;
  570. if (
  571. cacheEntry &&
  572. cacheEntry.needModule === needModule &&
  573. cacheEntry.needExports === needExports &&
  574. cacheEntry.needRequire === needRequire &&
  575. cacheEntry.needThisAsExports === needThisAsExports &&
  576. cacheEntry.needStrict === needStrict
  577. ) {
  578. source = cacheEntry.source;
  579. } else {
  580. const factorySource = new ConcatSource();
  581. const args = [];
  582. if (needExports || needRequire || needModule)
  583. args.push(
  584. needModule
  585. ? module.moduleArgument
  586. : `__unused_webpack_${module.moduleArgument}`
  587. );
  588. if (needExports || needRequire)
  589. args.push(
  590. needExports
  591. ? module.exportsArgument
  592. : `__unused_webpack_${module.exportsArgument}`
  593. );
  594. if (needRequire) args.push(RuntimeGlobals.require);
  595. if (!needThisAsExports && runtimeTemplate.supportsArrowFunction()) {
  596. factorySource.add(`/***/ ((${args.join(", ")}) => {\n\n`);
  597. } else {
  598. factorySource.add(`/***/ (function(${args.join(", ")}) {\n\n`);
  599. }
  600. if (needStrict) {
  601. factorySource.add('"use strict";\n');
  602. }
  603. factorySource.add(moduleSourcePostContent);
  604. factorySource.add("\n\n/***/ })");
  605. source = new CachedSource(factorySource);
  606. this._moduleFactoryCache.set(moduleSourcePostContent, {
  607. source,
  608. needModule,
  609. needExports,
  610. needRequire,
  611. needThisAsExports,
  612. needStrict
  613. });
  614. }
  615. moduleSourcePostContainer = tryRunOrWebpackError(
  616. () => hooks.renderModuleContainer.call(source, module, renderContext),
  617. "JavascriptModulesPlugin.getCompilationHooks().renderModuleContainer"
  618. );
  619. } else {
  620. moduleSourcePostContainer = moduleSourcePostContent;
  621. }
  622. return tryRunOrWebpackError(
  623. () =>
  624. hooks.renderModulePackage.call(
  625. moduleSourcePostContainer,
  626. module,
  627. renderContext
  628. ),
  629. "JavascriptModulesPlugin.getCompilationHooks().renderModulePackage"
  630. );
  631. } catch (err) {
  632. /** @type {WebpackError} */
  633. (err).module = module;
  634. throw err;
  635. }
  636. }
  637. /**
  638. * @param {RenderContext} renderContext the render context
  639. * @param {CompilationHooks} hooks hooks
  640. * @returns {Source} the rendered source
  641. */
  642. renderChunk(renderContext, hooks) {
  643. const { chunk, chunkGraph } = renderContext;
  644. const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
  645. chunk,
  646. "javascript",
  647. compareModulesByIdentifier
  648. );
  649. const allModules = modules ? Array.from(modules) : [];
  650. let strictHeader;
  651. let allStrict = renderContext.strictMode;
  652. if (
  653. !allStrict &&
  654. allModules.every(m => /** @type {BuildInfo} */ (m.buildInfo).strict)
  655. ) {
  656. const strictBailout = hooks.strictRuntimeBailout.call(renderContext);
  657. strictHeader = strictBailout
  658. ? `// runtime can't be in strict mode because ${strictBailout}.\n`
  659. : '"use strict";\n';
  660. if (!strictBailout) allStrict = true;
  661. }
  662. /** @type {ChunkRenderContext} */
  663. const chunkRenderContext = {
  664. ...renderContext,
  665. chunkInitFragments: [],
  666. strictMode: allStrict
  667. };
  668. const moduleSources =
  669. Template.renderChunkModules(chunkRenderContext, allModules, module =>
  670. this.renderModule(module, chunkRenderContext, hooks, true)
  671. ) || new RawSource("{}");
  672. let source = tryRunOrWebpackError(
  673. () => hooks.renderChunk.call(moduleSources, chunkRenderContext),
  674. "JavascriptModulesPlugin.getCompilationHooks().renderChunk"
  675. );
  676. source = tryRunOrWebpackError(
  677. () => hooks.renderContent.call(source, chunkRenderContext),
  678. "JavascriptModulesPlugin.getCompilationHooks().renderContent"
  679. );
  680. if (!source) {
  681. throw new Error(
  682. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something"
  683. );
  684. }
  685. source = InitFragment.addToSource(
  686. source,
  687. chunkRenderContext.chunkInitFragments,
  688. chunkRenderContext
  689. );
  690. source = tryRunOrWebpackError(
  691. () => hooks.render.call(source, chunkRenderContext),
  692. "JavascriptModulesPlugin.getCompilationHooks().render"
  693. );
  694. if (!source) {
  695. throw new Error(
  696. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().render plugins should return something"
  697. );
  698. }
  699. chunk.rendered = true;
  700. return strictHeader
  701. ? new ConcatSource(strictHeader, source, ";")
  702. : renderContext.runtimeTemplate.isModule()
  703. ? source
  704. : new ConcatSource(source, ";");
  705. }
  706. /**
  707. * @param {MainRenderContext} renderContext options object
  708. * @param {CompilationHooks} hooks hooks
  709. * @param {Compilation} compilation the compilation
  710. * @returns {Source} the newly generated source from rendering
  711. */
  712. renderMain(renderContext, hooks, compilation) {
  713. const { chunk, chunkGraph, runtimeTemplate } = renderContext;
  714. const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
  715. const iife = runtimeTemplate.isIIFE();
  716. const bootstrap = this.renderBootstrap(renderContext, hooks);
  717. const useSourceMap = hooks.useSourceMap.call(chunk, renderContext);
  718. const allModules = Array.from(
  719. chunkGraph.getOrderedChunkModulesIterableBySourceType(
  720. chunk,
  721. "javascript",
  722. compareModulesByIdentifier
  723. ) || []
  724. );
  725. const hasEntryModules = chunkGraph.getNumberOfEntryModules(chunk) > 0;
  726. /** @type {Set<Module> | undefined} */
  727. let inlinedModules;
  728. if (bootstrap.allowInlineStartup && hasEntryModules) {
  729. inlinedModules = new Set(chunkGraph.getChunkEntryModulesIterable(chunk));
  730. }
  731. const source = new ConcatSource();
  732. let prefix;
  733. if (iife) {
  734. if (runtimeTemplate.supportsArrowFunction()) {
  735. source.add("/******/ (() => { // webpackBootstrap\n");
  736. } else {
  737. source.add("/******/ (function() { // webpackBootstrap\n");
  738. }
  739. prefix = "/******/ \t";
  740. } else {
  741. prefix = "/******/ ";
  742. }
  743. let allStrict = renderContext.strictMode;
  744. if (
  745. !allStrict &&
  746. allModules.every(m => /** @type {BuildInfo} */ (m.buildInfo).strict)
  747. ) {
  748. const strictBailout = hooks.strictRuntimeBailout.call(renderContext);
  749. if (strictBailout) {
  750. source.add(
  751. `${
  752. prefix
  753. }// runtime can't be in strict mode because ${strictBailout}.\n`
  754. );
  755. } else {
  756. allStrict = true;
  757. source.add(`${prefix}"use strict";\n`);
  758. }
  759. }
  760. /** @type {ChunkRenderContext} */
  761. const chunkRenderContext = {
  762. ...renderContext,
  763. chunkInitFragments: [],
  764. strictMode: allStrict
  765. };
  766. const chunkModules = Template.renderChunkModules(
  767. chunkRenderContext,
  768. inlinedModules
  769. ? allModules.filter(
  770. m => !(/** @type {Set<Module>} */ (inlinedModules).has(m))
  771. )
  772. : allModules,
  773. module => this.renderModule(module, chunkRenderContext, hooks, true),
  774. prefix
  775. );
  776. if (
  777. chunkModules ||
  778. runtimeRequirements.has(RuntimeGlobals.moduleFactories) ||
  779. runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly) ||
  780. runtimeRequirements.has(RuntimeGlobals.require)
  781. ) {
  782. source.add(`${prefix}var __webpack_modules__ = (`);
  783. source.add(chunkModules || "{}");
  784. source.add(");\n");
  785. source.add(
  786. "/************************************************************************/\n"
  787. );
  788. }
  789. if (bootstrap.header.length > 0) {
  790. const header = `${Template.asString(bootstrap.header)}\n`;
  791. source.add(
  792. new PrefixSource(
  793. prefix,
  794. useSourceMap
  795. ? new OriginalSource(header, "webpack/bootstrap")
  796. : new RawSource(header)
  797. )
  798. );
  799. source.add(
  800. "/************************************************************************/\n"
  801. );
  802. }
  803. const runtimeModules =
  804. renderContext.chunkGraph.getChunkRuntimeModulesInOrder(chunk);
  805. if (runtimeModules.length > 0) {
  806. source.add(
  807. new PrefixSource(
  808. prefix,
  809. Template.renderRuntimeModules(runtimeModules, chunkRenderContext)
  810. )
  811. );
  812. source.add(
  813. "/************************************************************************/\n"
  814. );
  815. // runtimeRuntimeModules calls codeGeneration
  816. for (const module of runtimeModules) {
  817. compilation.codeGeneratedModules.add(module);
  818. }
  819. }
  820. if (inlinedModules) {
  821. if (bootstrap.beforeStartup.length > 0) {
  822. const beforeStartup = `${Template.asString(bootstrap.beforeStartup)}\n`;
  823. source.add(
  824. new PrefixSource(
  825. prefix,
  826. useSourceMap
  827. ? new OriginalSource(beforeStartup, "webpack/before-startup")
  828. : new RawSource(beforeStartup)
  829. )
  830. );
  831. }
  832. const lastInlinedModule = /** @type {Module} */ (last(inlinedModules));
  833. const startupSource = new ConcatSource();
  834. if (runtimeRequirements.has(RuntimeGlobals.exports)) {
  835. startupSource.add(`var ${RuntimeGlobals.exports} = {};\n`);
  836. }
  837. const avoidEntryIife = compilation.options.optimization.avoidEntryIife;
  838. /** @type {Map<Module, Source> | false} */
  839. let renamedInlinedModule = false;
  840. if (avoidEntryIife) {
  841. renamedInlinedModule = this.getRenamedInlineModule(
  842. allModules,
  843. renderContext,
  844. inlinedModules,
  845. chunkRenderContext,
  846. hooks,
  847. allStrict,
  848. Boolean(chunkModules)
  849. );
  850. }
  851. for (const m of inlinedModules) {
  852. const renderedModule = renamedInlinedModule
  853. ? renamedInlinedModule.get(m)
  854. : this.renderModule(m, chunkRenderContext, hooks, false);
  855. if (renderedModule) {
  856. const innerStrict =
  857. !allStrict && /** @type {BuildInfo} */ (m.buildInfo).strict;
  858. const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
  859. m,
  860. chunk.runtime
  861. );
  862. const exports = runtimeRequirements.has(RuntimeGlobals.exports);
  863. const webpackExports =
  864. exports && m.exportsArgument === RuntimeGlobals.exports;
  865. const iife = innerStrict
  866. ? "it needs to be in strict mode."
  867. : inlinedModules.size > 1
  868. ? // TODO check globals and top-level declarations of other entries and chunk modules
  869. // to make a better decision
  870. "it needs to be isolated against other entry modules."
  871. : chunkModules && !renamedInlinedModule
  872. ? "it needs to be isolated against other modules in the chunk."
  873. : exports && !webpackExports
  874. ? `it uses a non-standard name for the exports (${m.exportsArgument}).`
  875. : hooks.embedInRuntimeBailout.call(m, renderContext);
  876. let footer;
  877. if (iife !== undefined) {
  878. startupSource.add(
  879. `// This entry needs to be wrapped in an IIFE because ${iife}\n`
  880. );
  881. const arrow = runtimeTemplate.supportsArrowFunction();
  882. if (arrow) {
  883. startupSource.add("(() => {\n");
  884. footer = "\n})();\n\n";
  885. } else {
  886. startupSource.add("!function() {\n");
  887. footer = "\n}();\n";
  888. }
  889. if (innerStrict) startupSource.add('"use strict";\n');
  890. } else {
  891. footer = "\n";
  892. }
  893. if (exports) {
  894. if (m !== lastInlinedModule)
  895. startupSource.add(`var ${m.exportsArgument} = {};\n`);
  896. else if (m.exportsArgument !== RuntimeGlobals.exports)
  897. startupSource.add(
  898. `var ${m.exportsArgument} = ${RuntimeGlobals.exports};\n`
  899. );
  900. }
  901. startupSource.add(renderedModule);
  902. startupSource.add(footer);
  903. }
  904. }
  905. if (runtimeRequirements.has(RuntimeGlobals.onChunksLoaded)) {
  906. startupSource.add(
  907. `${RuntimeGlobals.exports} = ${RuntimeGlobals.onChunksLoaded}(${RuntimeGlobals.exports});\n`
  908. );
  909. }
  910. source.add(
  911. hooks.renderStartup.call(startupSource, lastInlinedModule, {
  912. ...renderContext,
  913. inlined: true
  914. })
  915. );
  916. if (bootstrap.afterStartup.length > 0) {
  917. const afterStartup = `${Template.asString(bootstrap.afterStartup)}\n`;
  918. source.add(
  919. new PrefixSource(
  920. prefix,
  921. useSourceMap
  922. ? new OriginalSource(afterStartup, "webpack/after-startup")
  923. : new RawSource(afterStartup)
  924. )
  925. );
  926. }
  927. } else {
  928. const lastEntryModule =
  929. /** @type {Module} */
  930. (last(chunkGraph.getChunkEntryModulesIterable(chunk)));
  931. /** @type {function(string[], string): Source} */
  932. const toSource = useSourceMap
  933. ? (content, name) =>
  934. new OriginalSource(Template.asString(content), name)
  935. : content => new RawSource(Template.asString(content));
  936. source.add(
  937. new PrefixSource(
  938. prefix,
  939. new ConcatSource(
  940. toSource(bootstrap.beforeStartup, "webpack/before-startup"),
  941. "\n",
  942. hooks.renderStartup.call(
  943. toSource(bootstrap.startup.concat(""), "webpack/startup"),
  944. lastEntryModule,
  945. {
  946. ...renderContext,
  947. inlined: false
  948. }
  949. ),
  950. toSource(bootstrap.afterStartup, "webpack/after-startup"),
  951. "\n"
  952. )
  953. )
  954. );
  955. }
  956. if (
  957. hasEntryModules &&
  958. runtimeRequirements.has(RuntimeGlobals.returnExportsFromRuntime)
  959. ) {
  960. source.add(`${prefix}return ${RuntimeGlobals.exports};\n`);
  961. }
  962. if (iife) {
  963. source.add("/******/ })()\n");
  964. }
  965. /** @type {Source} */
  966. let finalSource = tryRunOrWebpackError(
  967. () => hooks.renderMain.call(source, renderContext),
  968. "JavascriptModulesPlugin.getCompilationHooks().renderMain"
  969. );
  970. if (!finalSource) {
  971. throw new Error(
  972. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderMain plugins should return something"
  973. );
  974. }
  975. finalSource = tryRunOrWebpackError(
  976. () => hooks.renderContent.call(finalSource, renderContext),
  977. "JavascriptModulesPlugin.getCompilationHooks().renderContent"
  978. );
  979. if (!finalSource) {
  980. throw new Error(
  981. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something"
  982. );
  983. }
  984. finalSource = InitFragment.addToSource(
  985. finalSource,
  986. chunkRenderContext.chunkInitFragments,
  987. chunkRenderContext
  988. );
  989. finalSource = tryRunOrWebpackError(
  990. () => hooks.render.call(finalSource, renderContext),
  991. "JavascriptModulesPlugin.getCompilationHooks().render"
  992. );
  993. if (!finalSource) {
  994. throw new Error(
  995. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().render plugins should return something"
  996. );
  997. }
  998. chunk.rendered = true;
  999. return iife ? new ConcatSource(finalSource, ";") : finalSource;
  1000. }
  1001. /**
  1002. * @param {Hash} hash the hash to be updated
  1003. * @param {RenderBootstrapContext} renderContext options object
  1004. * @param {CompilationHooks} hooks hooks
  1005. */
  1006. updateHashWithBootstrap(hash, renderContext, hooks) {
  1007. const bootstrap = this.renderBootstrap(renderContext, hooks);
  1008. for (const _k of Object.keys(bootstrap)) {
  1009. const key = /** @type {keyof Bootstrap} */ (_k);
  1010. hash.update(key);
  1011. if (Array.isArray(bootstrap[key])) {
  1012. for (const line of bootstrap[key]) {
  1013. hash.update(line);
  1014. }
  1015. } else {
  1016. hash.update(JSON.stringify(bootstrap[key]));
  1017. }
  1018. }
  1019. }
  1020. /**
  1021. * @param {RenderBootstrapContext} renderContext options object
  1022. * @param {CompilationHooks} hooks hooks
  1023. * @returns {Bootstrap} the generated source of the bootstrap code
  1024. */
  1025. renderBootstrap(renderContext, hooks) {
  1026. const {
  1027. chunkGraph,
  1028. codeGenerationResults,
  1029. moduleGraph,
  1030. chunk,
  1031. runtimeTemplate
  1032. } = renderContext;
  1033. const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
  1034. const requireFunction = runtimeRequirements.has(RuntimeGlobals.require);
  1035. const moduleCache = runtimeRequirements.has(RuntimeGlobals.moduleCache);
  1036. const moduleFactories = runtimeRequirements.has(
  1037. RuntimeGlobals.moduleFactories
  1038. );
  1039. const moduleUsed = runtimeRequirements.has(RuntimeGlobals.module);
  1040. const requireScopeUsed = runtimeRequirements.has(
  1041. RuntimeGlobals.requireScope
  1042. );
  1043. const interceptModuleExecution = runtimeRequirements.has(
  1044. RuntimeGlobals.interceptModuleExecution
  1045. );
  1046. const useRequire =
  1047. requireFunction || interceptModuleExecution || moduleUsed;
  1048. /**
  1049. * @type {{startup: string[], beforeStartup: string[], header: string[], afterStartup: string[], allowInlineStartup: boolean}}
  1050. */
  1051. const result = {
  1052. header: [],
  1053. beforeStartup: [],
  1054. startup: [],
  1055. afterStartup: [],
  1056. allowInlineStartup: true
  1057. };
  1058. const { header: buf, startup, beforeStartup, afterStartup } = result;
  1059. if (result.allowInlineStartup && moduleFactories) {
  1060. startup.push(
  1061. "// module factories are used so entry inlining is disabled"
  1062. );
  1063. result.allowInlineStartup = false;
  1064. }
  1065. if (result.allowInlineStartup && moduleCache) {
  1066. startup.push("// module cache are used so entry inlining is disabled");
  1067. result.allowInlineStartup = false;
  1068. }
  1069. if (result.allowInlineStartup && interceptModuleExecution) {
  1070. startup.push(
  1071. "// module execution is intercepted so entry inlining is disabled"
  1072. );
  1073. result.allowInlineStartup = false;
  1074. }
  1075. if (useRequire || moduleCache) {
  1076. buf.push("// The module cache");
  1077. buf.push("var __webpack_module_cache__ = {};");
  1078. buf.push("");
  1079. }
  1080. if (useRequire) {
  1081. buf.push("// The require function");
  1082. buf.push(`function ${RuntimeGlobals.require}(moduleId) {`);
  1083. buf.push(Template.indent(this.renderRequire(renderContext, hooks)));
  1084. buf.push("}");
  1085. buf.push("");
  1086. } else if (runtimeRequirements.has(RuntimeGlobals.requireScope)) {
  1087. buf.push("// The require scope");
  1088. buf.push(`var ${RuntimeGlobals.require} = {};`);
  1089. buf.push("");
  1090. }
  1091. if (
  1092. moduleFactories ||
  1093. runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly)
  1094. ) {
  1095. buf.push("// expose the modules object (__webpack_modules__)");
  1096. buf.push(`${RuntimeGlobals.moduleFactories} = __webpack_modules__;`);
  1097. buf.push("");
  1098. }
  1099. if (moduleCache) {
  1100. buf.push("// expose the module cache");
  1101. buf.push(`${RuntimeGlobals.moduleCache} = __webpack_module_cache__;`);
  1102. buf.push("");
  1103. }
  1104. if (interceptModuleExecution) {
  1105. buf.push("// expose the module execution interceptor");
  1106. buf.push(`${RuntimeGlobals.interceptModuleExecution} = [];`);
  1107. buf.push("");
  1108. }
  1109. if (!runtimeRequirements.has(RuntimeGlobals.startupNoDefault)) {
  1110. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
  1111. /** @type {string[]} */
  1112. const buf2 = [];
  1113. const runtimeRequirements =
  1114. chunkGraph.getTreeRuntimeRequirements(chunk);
  1115. buf2.push("// Load entry module and return exports");
  1116. let i = chunkGraph.getNumberOfEntryModules(chunk);
  1117. for (const [
  1118. entryModule,
  1119. entrypoint
  1120. ] of chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)) {
  1121. if (!chunkGraph.getModuleSourceTypes(entryModule).has("javascript")) {
  1122. i--;
  1123. continue;
  1124. }
  1125. const chunks =
  1126. /** @type {Entrypoint} */
  1127. (entrypoint).chunks.filter(c => c !== chunk);
  1128. if (result.allowInlineStartup && chunks.length > 0) {
  1129. buf2.push(
  1130. "// This entry module depends on other loaded chunks and execution need to be delayed"
  1131. );
  1132. result.allowInlineStartup = false;
  1133. }
  1134. if (
  1135. result.allowInlineStartup &&
  1136. someInIterable(
  1137. moduleGraph.getIncomingConnectionsByOriginModule(entryModule),
  1138. ([originModule, connections]) =>
  1139. originModule &&
  1140. connections.some(c => c.isTargetActive(chunk.runtime)) &&
  1141. someInIterable(
  1142. chunkGraph.getModuleRuntimes(originModule),
  1143. runtime =>
  1144. intersectRuntime(runtime, chunk.runtime) !== undefined
  1145. )
  1146. )
  1147. ) {
  1148. buf2.push(
  1149. "// This entry module is referenced by other modules so it can't be inlined"
  1150. );
  1151. result.allowInlineStartup = false;
  1152. }
  1153. let data;
  1154. if (codeGenerationResults.has(entryModule, chunk.runtime)) {
  1155. const result = codeGenerationResults.get(
  1156. entryModule,
  1157. chunk.runtime
  1158. );
  1159. data = result.data;
  1160. }
  1161. if (
  1162. result.allowInlineStartup &&
  1163. (!data || !data.get("topLevelDeclarations")) &&
  1164. (!entryModule.buildInfo ||
  1165. !entryModule.buildInfo.topLevelDeclarations)
  1166. ) {
  1167. buf2.push(
  1168. "// This entry module doesn't tell about it's top-level declarations so it can't be inlined"
  1169. );
  1170. result.allowInlineStartup = false;
  1171. }
  1172. if (result.allowInlineStartup) {
  1173. const bailout = hooks.inlineInRuntimeBailout.call(
  1174. entryModule,
  1175. renderContext
  1176. );
  1177. if (bailout !== undefined) {
  1178. buf2.push(
  1179. `// This entry module can't be inlined because ${bailout}`
  1180. );
  1181. result.allowInlineStartup = false;
  1182. }
  1183. }
  1184. i--;
  1185. const moduleId = chunkGraph.getModuleId(entryModule);
  1186. const entryRuntimeRequirements =
  1187. chunkGraph.getModuleRuntimeRequirements(entryModule, chunk.runtime);
  1188. let moduleIdExpr = JSON.stringify(moduleId);
  1189. if (runtimeRequirements.has(RuntimeGlobals.entryModuleId)) {
  1190. moduleIdExpr = `${RuntimeGlobals.entryModuleId} = ${moduleIdExpr}`;
  1191. }
  1192. if (
  1193. result.allowInlineStartup &&
  1194. entryRuntimeRequirements.has(RuntimeGlobals.module)
  1195. ) {
  1196. result.allowInlineStartup = false;
  1197. buf2.push(
  1198. "// This entry module used 'module' so it can't be inlined"
  1199. );
  1200. }
  1201. if (chunks.length > 0) {
  1202. buf2.push(
  1203. `${i === 0 ? `var ${RuntimeGlobals.exports} = ` : ""}${
  1204. RuntimeGlobals.onChunksLoaded
  1205. }(undefined, ${JSON.stringify(
  1206. chunks.map(c => c.id)
  1207. )}, ${runtimeTemplate.returningFunction(
  1208. `${RuntimeGlobals.require}(${moduleIdExpr})`
  1209. )})`
  1210. );
  1211. } else if (useRequire) {
  1212. buf2.push(
  1213. `${i === 0 ? `var ${RuntimeGlobals.exports} = ` : ""}${
  1214. RuntimeGlobals.require
  1215. }(${moduleIdExpr});`
  1216. );
  1217. } else {
  1218. if (i === 0) buf2.push(`var ${RuntimeGlobals.exports} = {};`);
  1219. if (requireScopeUsed) {
  1220. buf2.push(
  1221. `__webpack_modules__[${moduleIdExpr}](0, ${
  1222. i === 0 ? RuntimeGlobals.exports : "{}"
  1223. }, ${RuntimeGlobals.require});`
  1224. );
  1225. } else if (entryRuntimeRequirements.has(RuntimeGlobals.exports)) {
  1226. buf2.push(
  1227. `__webpack_modules__[${moduleIdExpr}](0, ${
  1228. i === 0 ? RuntimeGlobals.exports : "{}"
  1229. });`
  1230. );
  1231. } else {
  1232. buf2.push(`__webpack_modules__[${moduleIdExpr}]();`);
  1233. }
  1234. }
  1235. }
  1236. if (runtimeRequirements.has(RuntimeGlobals.onChunksLoaded)) {
  1237. buf2.push(
  1238. `${RuntimeGlobals.exports} = ${RuntimeGlobals.onChunksLoaded}(${RuntimeGlobals.exports});`
  1239. );
  1240. }
  1241. if (
  1242. runtimeRequirements.has(RuntimeGlobals.startup) ||
  1243. (runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) &&
  1244. runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter))
  1245. ) {
  1246. result.allowInlineStartup = false;
  1247. buf.push("// the startup function");
  1248. buf.push(
  1249. `${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction("", [
  1250. ...buf2,
  1251. `return ${RuntimeGlobals.exports};`
  1252. ])};`
  1253. );
  1254. buf.push("");
  1255. startup.push("// run startup");
  1256. startup.push(
  1257. `var ${RuntimeGlobals.exports} = ${RuntimeGlobals.startup}();`
  1258. );
  1259. } else if (runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore)) {
  1260. buf.push("// the startup function");
  1261. buf.push(
  1262. `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
  1263. );
  1264. beforeStartup.push("// run runtime startup");
  1265. beforeStartup.push(`${RuntimeGlobals.startup}();`);
  1266. startup.push("// startup");
  1267. startup.push(Template.asString(buf2));
  1268. } else if (runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)) {
  1269. buf.push("// the startup function");
  1270. buf.push(
  1271. `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
  1272. );
  1273. startup.push("// startup");
  1274. startup.push(Template.asString(buf2));
  1275. afterStartup.push("// run runtime startup");
  1276. afterStartup.push(`${RuntimeGlobals.startup}();`);
  1277. } else {
  1278. startup.push("// startup");
  1279. startup.push(Template.asString(buf2));
  1280. }
  1281. } else if (
  1282. runtimeRequirements.has(RuntimeGlobals.startup) ||
  1283. runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) ||
  1284. runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)
  1285. ) {
  1286. buf.push(
  1287. "// the startup function",
  1288. "// It's empty as no entry modules are in this chunk",
  1289. `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`,
  1290. ""
  1291. );
  1292. }
  1293. } else if (
  1294. runtimeRequirements.has(RuntimeGlobals.startup) ||
  1295. runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) ||
  1296. runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)
  1297. ) {
  1298. result.allowInlineStartup = false;
  1299. buf.push(
  1300. "// the startup function",
  1301. "// It's empty as some runtime module handles the default behavior",
  1302. `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
  1303. );
  1304. startup.push("// run startup");
  1305. startup.push(
  1306. `var ${RuntimeGlobals.exports} = ${RuntimeGlobals.startup}();`
  1307. );
  1308. }
  1309. return result;
  1310. }
  1311. /**
  1312. * @param {RenderBootstrapContext} renderContext options object
  1313. * @param {CompilationHooks} hooks hooks
  1314. * @returns {string} the generated source of the require function
  1315. */
  1316. renderRequire(renderContext, hooks) {
  1317. const {
  1318. chunk,
  1319. chunkGraph,
  1320. runtimeTemplate: { outputOptions }
  1321. } = renderContext;
  1322. const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
  1323. const moduleExecution = runtimeRequirements.has(
  1324. RuntimeGlobals.interceptModuleExecution
  1325. )
  1326. ? Template.asString([
  1327. `var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: ${RuntimeGlobals.require} };`,
  1328. `${RuntimeGlobals.interceptModuleExecution}.forEach(function(handler) { handler(execOptions); });`,
  1329. "module = execOptions.module;",
  1330. "execOptions.factory.call(module.exports, module, module.exports, execOptions.require);"
  1331. ])
  1332. : runtimeRequirements.has(RuntimeGlobals.thisAsExports)
  1333. ? Template.asString([
  1334. `__webpack_modules__[moduleId].call(module.exports, module, module.exports, ${RuntimeGlobals.require});`
  1335. ])
  1336. : Template.asString([
  1337. `__webpack_modules__[moduleId](module, module.exports, ${RuntimeGlobals.require});`
  1338. ]);
  1339. const needModuleId = runtimeRequirements.has(RuntimeGlobals.moduleId);
  1340. const needModuleLoaded = runtimeRequirements.has(
  1341. RuntimeGlobals.moduleLoaded
  1342. );
  1343. const content = Template.asString([
  1344. "// Check if module is in cache",
  1345. "var cachedModule = __webpack_module_cache__[moduleId];",
  1346. "if (cachedModule !== undefined) {",
  1347. outputOptions.strictModuleErrorHandling
  1348. ? Template.indent([
  1349. "if (cachedModule.error !== undefined) throw cachedModule.error;",
  1350. "return cachedModule.exports;"
  1351. ])
  1352. : Template.indent("return cachedModule.exports;"),
  1353. "}",
  1354. "// Create a new module (and put it into the cache)",
  1355. "var module = __webpack_module_cache__[moduleId] = {",
  1356. Template.indent([
  1357. needModuleId ? "id: moduleId," : "// no module.id needed",
  1358. needModuleLoaded ? "loaded: false," : "// no module.loaded needed",
  1359. "exports: {}"
  1360. ]),
  1361. "};",
  1362. "",
  1363. outputOptions.strictModuleExceptionHandling
  1364. ? Template.asString([
  1365. "// Execute the module function",
  1366. "var threw = true;",
  1367. "try {",
  1368. Template.indent([moduleExecution, "threw = false;"]),
  1369. "} finally {",
  1370. Template.indent([
  1371. "if(threw) delete __webpack_module_cache__[moduleId];"
  1372. ]),
  1373. "}"
  1374. ])
  1375. : outputOptions.strictModuleErrorHandling
  1376. ? Template.asString([
  1377. "// Execute the module function",
  1378. "try {",
  1379. Template.indent(moduleExecution),
  1380. "} catch(e) {",
  1381. Template.indent(["module.error = e;", "throw e;"]),
  1382. "}"
  1383. ])
  1384. : Template.asString([
  1385. "// Execute the module function",
  1386. moduleExecution
  1387. ]),
  1388. needModuleLoaded
  1389. ? Template.asString([
  1390. "",
  1391. "// Flag the module as loaded",
  1392. `${RuntimeGlobals.moduleLoaded} = true;`,
  1393. ""
  1394. ])
  1395. : "",
  1396. "// Return the exports of the module",
  1397. "return module.exports;"
  1398. ]);
  1399. return tryRunOrWebpackError(
  1400. () => hooks.renderRequire.call(content, renderContext),
  1401. "JavascriptModulesPlugin.getCompilationHooks().renderRequire"
  1402. );
  1403. }
  1404. /**
  1405. * @param {Module[]} allModules allModules
  1406. * @param {MainRenderContext} renderContext renderContext
  1407. * @param {Set<Module>} inlinedModules inlinedModules
  1408. * @param {ChunkRenderContext} chunkRenderContext chunkRenderContext
  1409. * @param {CompilationHooks} hooks hooks
  1410. * @param {boolean | undefined} allStrict allStrict
  1411. * @param {boolean} hasChunkModules hasChunkModules
  1412. * @returns {Map<Module, Source> | false} renamed inlined modules
  1413. */
  1414. getRenamedInlineModule(
  1415. allModules,
  1416. renderContext,
  1417. inlinedModules,
  1418. chunkRenderContext,
  1419. hooks,
  1420. allStrict,
  1421. hasChunkModules
  1422. ) {
  1423. const innerStrict =
  1424. !allStrict &&
  1425. allModules.every(m => /** @type {BuildInfo} */ (m.buildInfo).strict);
  1426. const isMultipleEntries = inlinedModules.size > 1;
  1427. const singleEntryWithModules = inlinedModules.size === 1 && hasChunkModules;
  1428. // TODO:
  1429. // This step is before the IIFE reason calculation. Ideally, it should only be executed when this function can optimize the
  1430. // IIFE reason. Otherwise, it should directly return false. There are four reasons now, we have skipped two already, the left
  1431. // one is 'it uses a non-standard name for the exports'.
  1432. if (isMultipleEntries || innerStrict || !singleEntryWithModules) {
  1433. return false;
  1434. }
  1435. /** @type {Map<Module, Source>} */
  1436. const renamedInlinedModules = new Map();
  1437. const { runtimeTemplate } = renderContext;
  1438. /** @typedef {{ source: Source, module: Module, ast: any, variables: Set<Variable>, through: Set<Reference>, usedInNonInlined: Set<Variable>, moduleScope: Scope }} Info */
  1439. /** @type {Map<Module, Info>} */
  1440. const inlinedModulesToInfo = new Map();
  1441. /** @type {Set<string>} */
  1442. const nonInlinedModuleThroughIdentifiers = new Set();
  1443. /** @type {Map<Module, Source>} */
  1444. for (const m of allModules) {
  1445. const isInlinedModule = inlinedModules && inlinedModules.has(m);
  1446. const moduleSource = this.renderModule(
  1447. m,
  1448. chunkRenderContext,
  1449. hooks,
  1450. !isInlinedModule
  1451. );
  1452. if (!moduleSource) continue;
  1453. const code = /** @type {string} */ (moduleSource.source());
  1454. const ast = JavascriptParser._parse(code, {
  1455. sourceType: "auto"
  1456. });
  1457. const scopeManager = eslintScope.analyze(ast, {
  1458. ecmaVersion: 6,
  1459. sourceType: "module",
  1460. optimistic: true,
  1461. ignoreEval: true
  1462. });
  1463. const globalScope = /** @type {Scope} */ (scopeManager.acquire(ast));
  1464. if (inlinedModules && inlinedModules.has(m)) {
  1465. const moduleScope = globalScope.childScopes[0];
  1466. inlinedModulesToInfo.set(m, {
  1467. source: moduleSource,
  1468. ast,
  1469. module: m,
  1470. variables: new Set(moduleScope.variables),
  1471. through: new Set(moduleScope.through),
  1472. usedInNonInlined: new Set(),
  1473. moduleScope
  1474. });
  1475. } else {
  1476. for (const ref of globalScope.through) {
  1477. nonInlinedModuleThroughIdentifiers.add(ref.identifier.name);
  1478. }
  1479. }
  1480. }
  1481. for (const [, { variables, usedInNonInlined }] of inlinedModulesToInfo) {
  1482. for (const variable of variables) {
  1483. if (
  1484. nonInlinedModuleThroughIdentifiers.has(variable.name) ||
  1485. RESERVED_NAMES.has(variable.name)
  1486. ) {
  1487. usedInNonInlined.add(variable);
  1488. }
  1489. }
  1490. }
  1491. for (const [m, moduleInfo] of inlinedModulesToInfo) {
  1492. const { ast, source: _source, usedInNonInlined } = moduleInfo;
  1493. const source = new ReplaceSource(_source);
  1494. if (usedInNonInlined.size === 0) {
  1495. renamedInlinedModules.set(m, source);
  1496. continue;
  1497. }
  1498. const info = /** @type {Info} */ (inlinedModulesToInfo.get(m));
  1499. const allUsedNames = new Set(
  1500. Array.from(info.through, v => v.identifier.name)
  1501. );
  1502. for (const variable of usedInNonInlined) {
  1503. allUsedNames.add(variable.name);
  1504. }
  1505. for (const variable of info.variables) {
  1506. allUsedNames.add(variable.name);
  1507. const references = getAllReferences(variable);
  1508. const allIdentifiers = new Set(
  1509. references.map(r => r.identifier).concat(variable.identifiers)
  1510. );
  1511. const usedNamesInScopeInfo = new Map();
  1512. const ignoredScopes = new Set();
  1513. const name = variable.name;
  1514. const { usedNames, alreadyCheckedScopes } = getUsedNamesInScopeInfo(
  1515. usedNamesInScopeInfo,
  1516. info.module.identifier(),
  1517. name
  1518. );
  1519. if (allUsedNames.has(name) || usedNames.has(name)) {
  1520. const references = getAllReferences(variable);
  1521. for (const ref of references) {
  1522. addScopeSymbols(
  1523. ref.from,
  1524. usedNames,
  1525. alreadyCheckedScopes,
  1526. ignoredScopes
  1527. );
  1528. }
  1529. const newName = findNewName(
  1530. variable.name,
  1531. allUsedNames,
  1532. usedNames,
  1533. m.readableIdentifier(runtimeTemplate.requestShortener)
  1534. );
  1535. allUsedNames.add(newName);
  1536. for (const identifier of allIdentifiers) {
  1537. const r = /** @type {Range} */ (identifier.range);
  1538. const path = getPathInAst(ast, identifier);
  1539. if (path && path.length > 1) {
  1540. const maybeProperty =
  1541. path[1].type === "AssignmentPattern" && path[1].left === path[0]
  1542. ? path[2]
  1543. : path[1];
  1544. if (
  1545. maybeProperty.type === "Property" &&
  1546. maybeProperty.shorthand
  1547. ) {
  1548. source.insert(r[1], `: ${newName}`);
  1549. continue;
  1550. }
  1551. }
  1552. source.replace(r[0], r[1] - 1, newName);
  1553. }
  1554. } else {
  1555. allUsedNames.add(name);
  1556. }
  1557. }
  1558. renamedInlinedModules.set(m, source);
  1559. }
  1560. return renamedInlinedModules;
  1561. }
  1562. }
  1563. module.exports = JavascriptModulesPlugin;
  1564. module.exports.chunkHasJs = chunkHasJs;