JavascriptModulesPlugin.js 48 KB

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