JavascriptModulesPlugin.js 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551
  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.exports);
  417. set.add(RuntimeGlobals.require);
  418. }
  419. }
  420. );
  421. compilation.hooks.executeModule.tap(PLUGIN_NAME, (options, context) => {
  422. const source = options.codeGenerationResult.sources.get("javascript");
  423. if (source === undefined) return;
  424. const { module, moduleObject } = options;
  425. const code = source.source();
  426. const fn = vm.runInThisContext(
  427. `(function(${module.moduleArgument}, ${module.exportsArgument}, ${RuntimeGlobals.require}) {\n${code}\n/**/})`,
  428. {
  429. filename: module.identifier(),
  430. lineOffset: -1
  431. }
  432. );
  433. try {
  434. fn.call(
  435. moduleObject.exports,
  436. moduleObject,
  437. moduleObject.exports,
  438. context.__webpack_require__
  439. );
  440. } catch (e) {
  441. e.stack += printGeneratedCodeForStack(
  442. options.module,
  443. /** @type {string} */ (code)
  444. );
  445. throw e;
  446. }
  447. });
  448. compilation.hooks.executeModule.tap(PLUGIN_NAME, (options, context) => {
  449. const source = options.codeGenerationResult.sources.get("runtime");
  450. if (source === undefined) return;
  451. let code = source.source();
  452. if (typeof code !== "string") code = code.toString();
  453. const fn = vm.runInThisContext(
  454. `(function(${RuntimeGlobals.require}) {\n${code}\n/**/})`,
  455. {
  456. filename: options.module.identifier(),
  457. lineOffset: -1
  458. }
  459. );
  460. try {
  461. fn.call(null, context.__webpack_require__);
  462. } catch (e) {
  463. e.stack += printGeneratedCodeForStack(options.module, code);
  464. throw e;
  465. }
  466. });
  467. }
  468. );
  469. }
  470. static getChunkFilenameTemplate(chunk, outputOptions) {
  471. if (chunk.filenameTemplate) {
  472. return chunk.filenameTemplate;
  473. } else if (chunk instanceof HotUpdateChunk) {
  474. return outputOptions.hotUpdateChunkFilename;
  475. } else if (chunk.canBeInitial()) {
  476. return outputOptions.filename;
  477. } else {
  478. return outputOptions.chunkFilename;
  479. }
  480. }
  481. /**
  482. * @param {Module} module the rendered module
  483. * @param {ChunkRenderContext} renderContext options object
  484. * @param {CompilationHooks} hooks hooks
  485. * @param {boolean} factory true: renders as factory method, false: pure module content
  486. * @returns {Source} the newly generated source from rendering
  487. */
  488. renderModule(module, renderContext, hooks, factory) {
  489. const {
  490. chunk,
  491. chunkGraph,
  492. runtimeTemplate,
  493. codeGenerationResults,
  494. strictMode
  495. } = renderContext;
  496. try {
  497. const codeGenResult = codeGenerationResults.get(module, chunk.runtime);
  498. const moduleSource = codeGenResult.sources.get("javascript");
  499. if (!moduleSource) return null;
  500. if (codeGenResult.data !== undefined) {
  501. const chunkInitFragments = codeGenResult.data.get("chunkInitFragments");
  502. if (chunkInitFragments) {
  503. for (const i of chunkInitFragments)
  504. renderContext.chunkInitFragments.push(i);
  505. }
  506. }
  507. const moduleSourcePostContent = tryRunOrWebpackError(
  508. () =>
  509. hooks.renderModuleContent.call(moduleSource, module, renderContext),
  510. "JavascriptModulesPlugin.getCompilationHooks().renderModuleContent"
  511. );
  512. let moduleSourcePostContainer;
  513. if (factory) {
  514. const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
  515. module,
  516. chunk.runtime
  517. );
  518. const needModule = runtimeRequirements.has(RuntimeGlobals.module);
  519. const needExports = runtimeRequirements.has(RuntimeGlobals.exports);
  520. const needRequire =
  521. runtimeRequirements.has(RuntimeGlobals.require) ||
  522. runtimeRequirements.has(RuntimeGlobals.requireScope);
  523. const needThisAsExports = runtimeRequirements.has(
  524. RuntimeGlobals.thisAsExports
  525. );
  526. const needStrict = module.buildInfo.strict && !strictMode;
  527. const cacheEntry = this._moduleFactoryCache.get(
  528. moduleSourcePostContent
  529. );
  530. let source;
  531. if (
  532. cacheEntry &&
  533. cacheEntry.needModule === needModule &&
  534. cacheEntry.needExports === needExports &&
  535. cacheEntry.needRequire === needRequire &&
  536. cacheEntry.needThisAsExports === needThisAsExports &&
  537. cacheEntry.needStrict === needStrict
  538. ) {
  539. source = cacheEntry.source;
  540. } else {
  541. const factorySource = new ConcatSource();
  542. const args = [];
  543. if (needExports || needRequire || needModule)
  544. args.push(
  545. needModule
  546. ? module.moduleArgument
  547. : "__unused_webpack_" + module.moduleArgument
  548. );
  549. if (needExports || needRequire)
  550. args.push(
  551. needExports
  552. ? module.exportsArgument
  553. : "__unused_webpack_" + module.exportsArgument
  554. );
  555. if (needRequire) args.push(RuntimeGlobals.require);
  556. if (!needThisAsExports && runtimeTemplate.supportsArrowFunction()) {
  557. factorySource.add("/***/ ((" + args.join(", ") + ") => {\n\n");
  558. } else {
  559. factorySource.add("/***/ (function(" + args.join(", ") + ") {\n\n");
  560. }
  561. if (needStrict) {
  562. factorySource.add('"use strict";\n');
  563. }
  564. factorySource.add(moduleSourcePostContent);
  565. factorySource.add("\n\n/***/ })");
  566. source = new CachedSource(factorySource);
  567. this._moduleFactoryCache.set(moduleSourcePostContent, {
  568. source,
  569. needModule,
  570. needExports,
  571. needRequire,
  572. needThisAsExports,
  573. needStrict
  574. });
  575. }
  576. moduleSourcePostContainer = tryRunOrWebpackError(
  577. () => hooks.renderModuleContainer.call(source, module, renderContext),
  578. "JavascriptModulesPlugin.getCompilationHooks().renderModuleContainer"
  579. );
  580. } else {
  581. moduleSourcePostContainer = moduleSourcePostContent;
  582. }
  583. return tryRunOrWebpackError(
  584. () =>
  585. hooks.renderModulePackage.call(
  586. moduleSourcePostContainer,
  587. module,
  588. renderContext
  589. ),
  590. "JavascriptModulesPlugin.getCompilationHooks().renderModulePackage"
  591. );
  592. } catch (e) {
  593. e.module = module;
  594. throw e;
  595. }
  596. }
  597. /**
  598. * @param {RenderContext} renderContext the render context
  599. * @param {CompilationHooks} hooks hooks
  600. * @returns {Source} the rendered source
  601. */
  602. renderChunk(renderContext, hooks) {
  603. const { chunk, chunkGraph } = renderContext;
  604. const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
  605. chunk,
  606. "javascript",
  607. compareModulesByIdentifier
  608. );
  609. const allModules = modules ? Array.from(modules) : [];
  610. let strictHeader;
  611. let allStrict = renderContext.strictMode;
  612. if (!allStrict && allModules.every(m => m.buildInfo.strict)) {
  613. const strictBailout = hooks.strictRuntimeBailout.call(renderContext);
  614. strictHeader = strictBailout
  615. ? `// runtime can't be in strict mode because ${strictBailout}.\n`
  616. : '"use strict";\n';
  617. if (!strictBailout) allStrict = true;
  618. }
  619. /** @type {ChunkRenderContext} */
  620. const chunkRenderContext = {
  621. ...renderContext,
  622. chunkInitFragments: [],
  623. strictMode: allStrict
  624. };
  625. const moduleSources =
  626. Template.renderChunkModules(chunkRenderContext, allModules, module =>
  627. this.renderModule(module, chunkRenderContext, hooks, true)
  628. ) || new RawSource("{}");
  629. let source = tryRunOrWebpackError(
  630. () => hooks.renderChunk.call(moduleSources, chunkRenderContext),
  631. "JavascriptModulesPlugin.getCompilationHooks().renderChunk"
  632. );
  633. source = tryRunOrWebpackError(
  634. () => hooks.renderContent.call(source, chunkRenderContext),
  635. "JavascriptModulesPlugin.getCompilationHooks().renderContent"
  636. );
  637. if (!source) {
  638. throw new Error(
  639. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something"
  640. );
  641. }
  642. source = InitFragment.addToSource(
  643. source,
  644. chunkRenderContext.chunkInitFragments,
  645. chunkRenderContext
  646. );
  647. source = tryRunOrWebpackError(
  648. () => hooks.render.call(source, chunkRenderContext),
  649. "JavascriptModulesPlugin.getCompilationHooks().render"
  650. );
  651. if (!source) {
  652. throw new Error(
  653. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().render plugins should return something"
  654. );
  655. }
  656. chunk.rendered = true;
  657. return strictHeader
  658. ? new ConcatSource(strictHeader, source, ";")
  659. : renderContext.runtimeTemplate.isModule()
  660. ? source
  661. : new ConcatSource(source, ";");
  662. }
  663. /**
  664. * @param {MainRenderContext} renderContext options object
  665. * @param {CompilationHooks} hooks hooks
  666. * @param {Compilation} compilation the compilation
  667. * @returns {Source} the newly generated source from rendering
  668. */
  669. renderMain(renderContext, hooks, compilation) {
  670. const { chunk, chunkGraph, runtimeTemplate } = renderContext;
  671. const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
  672. const iife = runtimeTemplate.isIIFE();
  673. const bootstrap = this.renderBootstrap(renderContext, hooks);
  674. const useSourceMap = hooks.useSourceMap.call(chunk, renderContext);
  675. const allModules = Array.from(
  676. chunkGraph.getOrderedChunkModulesIterableBySourceType(
  677. chunk,
  678. "javascript",
  679. compareModulesByIdentifier
  680. ) || []
  681. );
  682. const hasEntryModules = chunkGraph.getNumberOfEntryModules(chunk) > 0;
  683. /** @type {Set<Module> | undefined} */
  684. let inlinedModules;
  685. if (bootstrap.allowInlineStartup && hasEntryModules) {
  686. inlinedModules = new Set(chunkGraph.getChunkEntryModulesIterable(chunk));
  687. }
  688. let source = new ConcatSource();
  689. let prefix;
  690. if (iife) {
  691. if (runtimeTemplate.supportsArrowFunction()) {
  692. source.add("/******/ (() => { // webpackBootstrap\n");
  693. } else {
  694. source.add("/******/ (function() { // webpackBootstrap\n");
  695. }
  696. prefix = "/******/ \t";
  697. } else {
  698. prefix = "/******/ ";
  699. }
  700. let allStrict = renderContext.strictMode;
  701. if (!allStrict && allModules.every(m => m.buildInfo.strict)) {
  702. const strictBailout = hooks.strictRuntimeBailout.call(renderContext);
  703. if (strictBailout) {
  704. source.add(
  705. prefix +
  706. `// runtime can't be in strict mode because ${strictBailout}.\n`
  707. );
  708. } else {
  709. allStrict = true;
  710. source.add(prefix + '"use strict";\n');
  711. }
  712. }
  713. /** @type {ChunkRenderContext} */
  714. const chunkRenderContext = {
  715. ...renderContext,
  716. chunkInitFragments: [],
  717. strictMode: allStrict
  718. };
  719. const chunkModules = Template.renderChunkModules(
  720. chunkRenderContext,
  721. inlinedModules
  722. ? allModules.filter(
  723. m => !(/** @type {Set<Module>} */ (inlinedModules).has(m))
  724. )
  725. : allModules,
  726. module => this.renderModule(module, chunkRenderContext, hooks, true),
  727. prefix
  728. );
  729. if (
  730. chunkModules ||
  731. runtimeRequirements.has(RuntimeGlobals.moduleFactories) ||
  732. runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly) ||
  733. runtimeRequirements.has(RuntimeGlobals.require)
  734. ) {
  735. source.add(prefix + "var __webpack_modules__ = (");
  736. source.add(chunkModules || "{}");
  737. source.add(");\n");
  738. source.add(
  739. "/************************************************************************/\n"
  740. );
  741. }
  742. if (bootstrap.header.length > 0) {
  743. const header = Template.asString(bootstrap.header) + "\n";
  744. source.add(
  745. new PrefixSource(
  746. prefix,
  747. useSourceMap
  748. ? new OriginalSource(header, "webpack/bootstrap")
  749. : new RawSource(header)
  750. )
  751. );
  752. source.add(
  753. "/************************************************************************/\n"
  754. );
  755. }
  756. const runtimeModules =
  757. renderContext.chunkGraph.getChunkRuntimeModulesInOrder(chunk);
  758. if (runtimeModules.length > 0) {
  759. source.add(
  760. new PrefixSource(
  761. prefix,
  762. Template.renderRuntimeModules(runtimeModules, chunkRenderContext)
  763. )
  764. );
  765. source.add(
  766. "/************************************************************************/\n"
  767. );
  768. // runtimeRuntimeModules calls codeGeneration
  769. for (const module of runtimeModules) {
  770. compilation.codeGeneratedModules.add(module);
  771. }
  772. }
  773. if (inlinedModules) {
  774. if (bootstrap.beforeStartup.length > 0) {
  775. const beforeStartup = Template.asString(bootstrap.beforeStartup) + "\n";
  776. source.add(
  777. new PrefixSource(
  778. prefix,
  779. useSourceMap
  780. ? new OriginalSource(beforeStartup, "webpack/before-startup")
  781. : new RawSource(beforeStartup)
  782. )
  783. );
  784. }
  785. const lastInlinedModule = last(inlinedModules);
  786. const startupSource = new ConcatSource();
  787. if (runtimeRequirements.has(RuntimeGlobals.exports)) {
  788. startupSource.add(`var ${RuntimeGlobals.exports} = {};\n`);
  789. }
  790. const renamedInlinedModule = this.renameInlineModule(
  791. allModules,
  792. renderContext,
  793. inlinedModules,
  794. chunkRenderContext,
  795. hooks
  796. );
  797. for (const m of inlinedModules) {
  798. const renderedModule =
  799. renamedInlinedModule.get(m) ||
  800. this.renderModule(m, chunkRenderContext, hooks, false);
  801. if (renderedModule) {
  802. const innerStrict = !allStrict && m.buildInfo.strict;
  803. const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
  804. m,
  805. chunk.runtime
  806. );
  807. const exports = runtimeRequirements.has(RuntimeGlobals.exports);
  808. const webpackExports =
  809. exports && m.exportsArgument === RuntimeGlobals.exports;
  810. let iife = innerStrict
  811. ? "it need to be in strict mode."
  812. : inlinedModules.size > 1
  813. ? // TODO check globals and top-level declarations of other entries and chunk modules
  814. // to make a better decision
  815. "it need to be isolated against other entry modules."
  816. : exports && !webpackExports
  817. ? `it uses a non-standard name for the exports (${m.exportsArgument}).`
  818. : hooks.embedInRuntimeBailout.call(m, renderContext);
  819. let footer;
  820. if (iife !== undefined) {
  821. startupSource.add(
  822. `// This entry need to be wrapped in an IIFE because ${iife}\n`
  823. );
  824. const arrow = runtimeTemplate.supportsArrowFunction();
  825. if (arrow) {
  826. startupSource.add("(() => {\n");
  827. footer = "\n})();\n\n";
  828. } else {
  829. startupSource.add("!function() {\n");
  830. footer = "\n}();\n";
  831. }
  832. if (innerStrict) startupSource.add('"use strict";\n');
  833. } else {
  834. footer = "\n";
  835. }
  836. if (exports) {
  837. if (m !== lastInlinedModule)
  838. startupSource.add(`var ${m.exportsArgument} = {};\n`);
  839. else if (m.exportsArgument !== RuntimeGlobals.exports)
  840. startupSource.add(
  841. `var ${m.exportsArgument} = ${RuntimeGlobals.exports};\n`
  842. );
  843. }
  844. startupSource.add(renderedModule);
  845. startupSource.add(footer);
  846. }
  847. }
  848. if (runtimeRequirements.has(RuntimeGlobals.onChunksLoaded)) {
  849. startupSource.add(
  850. `${RuntimeGlobals.exports} = ${RuntimeGlobals.onChunksLoaded}(${RuntimeGlobals.exports});\n`
  851. );
  852. }
  853. source.add(
  854. hooks.renderStartup.call(startupSource, lastInlinedModule, {
  855. ...renderContext,
  856. inlined: true
  857. })
  858. );
  859. if (bootstrap.afterStartup.length > 0) {
  860. const afterStartup = Template.asString(bootstrap.afterStartup) + "\n";
  861. source.add(
  862. new PrefixSource(
  863. prefix,
  864. useSourceMap
  865. ? new OriginalSource(afterStartup, "webpack/after-startup")
  866. : new RawSource(afterStartup)
  867. )
  868. );
  869. }
  870. } else {
  871. const lastEntryModule = last(
  872. chunkGraph.getChunkEntryModulesIterable(chunk)
  873. );
  874. const toSource = useSourceMap
  875. ? (content, name) =>
  876. new OriginalSource(Template.asString(content), name)
  877. : content => new RawSource(Template.asString(content));
  878. source.add(
  879. new PrefixSource(
  880. prefix,
  881. new ConcatSource(
  882. toSource(bootstrap.beforeStartup, "webpack/before-startup"),
  883. "\n",
  884. hooks.renderStartup.call(
  885. toSource(bootstrap.startup.concat(""), "webpack/startup"),
  886. lastEntryModule,
  887. {
  888. ...renderContext,
  889. inlined: false
  890. }
  891. ),
  892. toSource(bootstrap.afterStartup, "webpack/after-startup"),
  893. "\n"
  894. )
  895. )
  896. );
  897. }
  898. if (
  899. hasEntryModules &&
  900. runtimeRequirements.has(RuntimeGlobals.returnExportsFromRuntime)
  901. ) {
  902. source.add(`${prefix}return ${RuntimeGlobals.exports};\n`);
  903. }
  904. if (iife) {
  905. source.add("/******/ })()\n");
  906. }
  907. /** @type {Source} */
  908. let finalSource = tryRunOrWebpackError(
  909. () => hooks.renderMain.call(source, renderContext),
  910. "JavascriptModulesPlugin.getCompilationHooks().renderMain"
  911. );
  912. if (!finalSource) {
  913. throw new Error(
  914. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderMain plugins should return something"
  915. );
  916. }
  917. finalSource = tryRunOrWebpackError(
  918. () => hooks.renderContent.call(finalSource, renderContext),
  919. "JavascriptModulesPlugin.getCompilationHooks().renderContent"
  920. );
  921. if (!finalSource) {
  922. throw new Error(
  923. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something"
  924. );
  925. }
  926. finalSource = InitFragment.addToSource(
  927. finalSource,
  928. chunkRenderContext.chunkInitFragments,
  929. chunkRenderContext
  930. );
  931. finalSource = tryRunOrWebpackError(
  932. () => hooks.render.call(finalSource, renderContext),
  933. "JavascriptModulesPlugin.getCompilationHooks().render"
  934. );
  935. if (!finalSource) {
  936. throw new Error(
  937. "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().render plugins should return something"
  938. );
  939. }
  940. chunk.rendered = true;
  941. return iife ? new ConcatSource(finalSource, ";") : finalSource;
  942. }
  943. /**
  944. * @param {Hash} hash the hash to be updated
  945. * @param {RenderBootstrapContext} renderContext options object
  946. * @param {CompilationHooks} hooks hooks
  947. */
  948. updateHashWithBootstrap(hash, renderContext, hooks) {
  949. const bootstrap = this.renderBootstrap(renderContext, hooks);
  950. for (const key of Object.keys(bootstrap)) {
  951. hash.update(key);
  952. if (Array.isArray(bootstrap[key])) {
  953. for (const line of bootstrap[key]) {
  954. hash.update(line);
  955. }
  956. } else {
  957. hash.update(JSON.stringify(bootstrap[key]));
  958. }
  959. }
  960. }
  961. /**
  962. * @param {RenderBootstrapContext} renderContext options object
  963. * @param {CompilationHooks} hooks hooks
  964. * @returns {{ header: string[], beforeStartup: string[], startup: string[], afterStartup: string[], allowInlineStartup: boolean }} the generated source of the bootstrap code
  965. */
  966. renderBootstrap(renderContext, hooks) {
  967. const {
  968. chunkGraph,
  969. codeGenerationResults,
  970. moduleGraph,
  971. chunk,
  972. runtimeTemplate
  973. } = renderContext;
  974. const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
  975. const requireFunction = runtimeRequirements.has(RuntimeGlobals.require);
  976. const moduleCache = runtimeRequirements.has(RuntimeGlobals.moduleCache);
  977. const moduleFactories = runtimeRequirements.has(
  978. RuntimeGlobals.moduleFactories
  979. );
  980. const moduleUsed = runtimeRequirements.has(RuntimeGlobals.module);
  981. const requireScopeUsed = runtimeRequirements.has(
  982. RuntimeGlobals.requireScope
  983. );
  984. const interceptModuleExecution = runtimeRequirements.has(
  985. RuntimeGlobals.interceptModuleExecution
  986. );
  987. const useRequire =
  988. requireFunction || interceptModuleExecution || moduleUsed;
  989. /**
  990. * @type {{startup: string[], beforeStartup: string[], header: string[], afterStartup: string[], allowInlineStartup: boolean}}
  991. */
  992. const result = {
  993. header: [],
  994. beforeStartup: [],
  995. startup: [],
  996. afterStartup: [],
  997. allowInlineStartup: true
  998. };
  999. let { header: buf, startup, beforeStartup, afterStartup } = result;
  1000. if (result.allowInlineStartup && moduleFactories) {
  1001. startup.push(
  1002. "// module factories are used so entry inlining is disabled"
  1003. );
  1004. result.allowInlineStartup = false;
  1005. }
  1006. if (result.allowInlineStartup && moduleCache) {
  1007. startup.push("// module cache are used so entry inlining is disabled");
  1008. result.allowInlineStartup = false;
  1009. }
  1010. if (result.allowInlineStartup && interceptModuleExecution) {
  1011. startup.push(
  1012. "// module execution is intercepted so entry inlining is disabled"
  1013. );
  1014. result.allowInlineStartup = false;
  1015. }
  1016. if (useRequire || moduleCache) {
  1017. buf.push("// The module cache");
  1018. buf.push("var __webpack_module_cache__ = {};");
  1019. buf.push("");
  1020. }
  1021. if (useRequire) {
  1022. buf.push("// The require function");
  1023. buf.push(`function ${RuntimeGlobals.require}(moduleId) {`);
  1024. buf.push(Template.indent(this.renderRequire(renderContext, hooks)));
  1025. buf.push("}");
  1026. buf.push("");
  1027. } else if (runtimeRequirements.has(RuntimeGlobals.requireScope)) {
  1028. buf.push("// The require scope");
  1029. buf.push(`var ${RuntimeGlobals.require} = {};`);
  1030. buf.push("");
  1031. }
  1032. if (
  1033. moduleFactories ||
  1034. runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly)
  1035. ) {
  1036. buf.push("// expose the modules object (__webpack_modules__)");
  1037. buf.push(`${RuntimeGlobals.moduleFactories} = __webpack_modules__;`);
  1038. buf.push("");
  1039. }
  1040. if (moduleCache) {
  1041. buf.push("// expose the module cache");
  1042. buf.push(`${RuntimeGlobals.moduleCache} = __webpack_module_cache__;`);
  1043. buf.push("");
  1044. }
  1045. if (interceptModuleExecution) {
  1046. buf.push("// expose the module execution interceptor");
  1047. buf.push(`${RuntimeGlobals.interceptModuleExecution} = [];`);
  1048. buf.push("");
  1049. }
  1050. if (!runtimeRequirements.has(RuntimeGlobals.startupNoDefault)) {
  1051. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
  1052. /** @type {string[]} */
  1053. const buf2 = [];
  1054. const runtimeRequirements =
  1055. chunkGraph.getTreeRuntimeRequirements(chunk);
  1056. buf2.push("// Load entry module and return exports");
  1057. let i = chunkGraph.getNumberOfEntryModules(chunk);
  1058. for (const [
  1059. entryModule,
  1060. entrypoint
  1061. ] of chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)) {
  1062. const chunks = entrypoint.chunks.filter(c => c !== chunk);
  1063. if (result.allowInlineStartup && chunks.length > 0) {
  1064. buf2.push(
  1065. "// This entry module depends on other loaded chunks and execution need to be delayed"
  1066. );
  1067. result.allowInlineStartup = false;
  1068. }
  1069. if (
  1070. result.allowInlineStartup &&
  1071. someInIterable(
  1072. moduleGraph.getIncomingConnectionsByOriginModule(entryModule),
  1073. ([originModule, connections]) =>
  1074. originModule &&
  1075. connections.some(c => c.isTargetActive(chunk.runtime)) &&
  1076. someInIterable(
  1077. chunkGraph.getModuleRuntimes(originModule),
  1078. runtime =>
  1079. intersectRuntime(runtime, chunk.runtime) !== undefined
  1080. )
  1081. )
  1082. ) {
  1083. buf2.push(
  1084. "// This entry module is referenced by other modules so it can't be inlined"
  1085. );
  1086. result.allowInlineStartup = false;
  1087. }
  1088. let data;
  1089. if (codeGenerationResults.has(entryModule, chunk.runtime)) {
  1090. const result = codeGenerationResults.get(
  1091. entryModule,
  1092. chunk.runtime
  1093. );
  1094. data = result.data;
  1095. }
  1096. if (
  1097. result.allowInlineStartup &&
  1098. (!data || !data.get("topLevelDeclarations")) &&
  1099. (!entryModule.buildInfo ||
  1100. !entryModule.buildInfo.topLevelDeclarations)
  1101. ) {
  1102. buf2.push(
  1103. "// This entry module doesn't tell about it's top-level declarations so it can't be inlined"
  1104. );
  1105. result.allowInlineStartup = false;
  1106. }
  1107. if (result.allowInlineStartup) {
  1108. const bailout = hooks.inlineInRuntimeBailout.call(
  1109. entryModule,
  1110. renderContext
  1111. );
  1112. if (bailout !== undefined) {
  1113. buf2.push(
  1114. `// This entry module can't be inlined because ${bailout}`
  1115. );
  1116. result.allowInlineStartup = false;
  1117. }
  1118. }
  1119. i--;
  1120. const moduleId = chunkGraph.getModuleId(entryModule);
  1121. const entryRuntimeRequirements =
  1122. chunkGraph.getModuleRuntimeRequirements(entryModule, chunk.runtime);
  1123. let moduleIdExpr = JSON.stringify(moduleId);
  1124. if (runtimeRequirements.has(RuntimeGlobals.entryModuleId)) {
  1125. moduleIdExpr = `${RuntimeGlobals.entryModuleId} = ${moduleIdExpr}`;
  1126. }
  1127. if (
  1128. result.allowInlineStartup &&
  1129. entryRuntimeRequirements.has(RuntimeGlobals.module)
  1130. ) {
  1131. result.allowInlineStartup = false;
  1132. buf2.push(
  1133. "// This entry module used 'module' so it can't be inlined"
  1134. );
  1135. }
  1136. if (chunks.length > 0) {
  1137. buf2.push(
  1138. `${i === 0 ? `var ${RuntimeGlobals.exports} = ` : ""}${
  1139. RuntimeGlobals.onChunksLoaded
  1140. }(undefined, ${JSON.stringify(
  1141. chunks.map(c => c.id)
  1142. )}, ${runtimeTemplate.returningFunction(
  1143. `${RuntimeGlobals.require}(${moduleIdExpr})`
  1144. )})`
  1145. );
  1146. } else if (useRequire) {
  1147. buf2.push(
  1148. `${i === 0 ? `var ${RuntimeGlobals.exports} = ` : ""}${
  1149. RuntimeGlobals.require
  1150. }(${moduleIdExpr});`
  1151. );
  1152. } else {
  1153. if (i === 0) buf2.push(`var ${RuntimeGlobals.exports} = {};`);
  1154. if (requireScopeUsed) {
  1155. buf2.push(
  1156. `__webpack_modules__[${moduleIdExpr}](0, ${
  1157. i === 0 ? RuntimeGlobals.exports : "{}"
  1158. }, ${RuntimeGlobals.require});`
  1159. );
  1160. } else if (entryRuntimeRequirements.has(RuntimeGlobals.exports)) {
  1161. buf2.push(
  1162. `__webpack_modules__[${moduleIdExpr}](0, ${
  1163. i === 0 ? RuntimeGlobals.exports : "{}"
  1164. });`
  1165. );
  1166. } else {
  1167. buf2.push(`__webpack_modules__[${moduleIdExpr}]();`);
  1168. }
  1169. }
  1170. }
  1171. if (runtimeRequirements.has(RuntimeGlobals.onChunksLoaded)) {
  1172. buf2.push(
  1173. `${RuntimeGlobals.exports} = ${RuntimeGlobals.onChunksLoaded}(${RuntimeGlobals.exports});`
  1174. );
  1175. }
  1176. if (
  1177. runtimeRequirements.has(RuntimeGlobals.startup) ||
  1178. (runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) &&
  1179. runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter))
  1180. ) {
  1181. result.allowInlineStartup = false;
  1182. buf.push("// the startup function");
  1183. buf.push(
  1184. `${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction("", [
  1185. ...buf2,
  1186. `return ${RuntimeGlobals.exports};`
  1187. ])};`
  1188. );
  1189. buf.push("");
  1190. startup.push("// run startup");
  1191. startup.push(
  1192. `var ${RuntimeGlobals.exports} = ${RuntimeGlobals.startup}();`
  1193. );
  1194. } else if (runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore)) {
  1195. buf.push("// the startup function");
  1196. buf.push(
  1197. `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
  1198. );
  1199. beforeStartup.push("// run runtime startup");
  1200. beforeStartup.push(`${RuntimeGlobals.startup}();`);
  1201. startup.push("// startup");
  1202. startup.push(Template.asString(buf2));
  1203. } else if (runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)) {
  1204. buf.push("// the startup function");
  1205. buf.push(
  1206. `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
  1207. );
  1208. startup.push("// startup");
  1209. startup.push(Template.asString(buf2));
  1210. afterStartup.push("// run runtime startup");
  1211. afterStartup.push(`${RuntimeGlobals.startup}();`);
  1212. } else {
  1213. startup.push("// startup");
  1214. startup.push(Template.asString(buf2));
  1215. }
  1216. } else if (
  1217. runtimeRequirements.has(RuntimeGlobals.startup) ||
  1218. runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) ||
  1219. runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)
  1220. ) {
  1221. buf.push(
  1222. "// the startup function",
  1223. "// It's empty as no entry modules are in this chunk",
  1224. `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`,
  1225. ""
  1226. );
  1227. }
  1228. } else if (
  1229. runtimeRequirements.has(RuntimeGlobals.startup) ||
  1230. runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) ||
  1231. runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)
  1232. ) {
  1233. result.allowInlineStartup = false;
  1234. buf.push(
  1235. "// the startup function",
  1236. "// It's empty as some runtime module handles the default behavior",
  1237. `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
  1238. );
  1239. startup.push("// run startup");
  1240. startup.push(
  1241. `var ${RuntimeGlobals.exports} = ${RuntimeGlobals.startup}();`
  1242. );
  1243. }
  1244. return result;
  1245. }
  1246. /**
  1247. * @param {RenderBootstrapContext} renderContext options object
  1248. * @param {CompilationHooks} hooks hooks
  1249. * @returns {string} the generated source of the require function
  1250. */
  1251. renderRequire(renderContext, hooks) {
  1252. const {
  1253. chunk,
  1254. chunkGraph,
  1255. runtimeTemplate: { outputOptions }
  1256. } = renderContext;
  1257. const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
  1258. const moduleExecution = runtimeRequirements.has(
  1259. RuntimeGlobals.interceptModuleExecution
  1260. )
  1261. ? Template.asString([
  1262. `var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: ${RuntimeGlobals.require} };`,
  1263. `${RuntimeGlobals.interceptModuleExecution}.forEach(function(handler) { handler(execOptions); });`,
  1264. "module = execOptions.module;",
  1265. "execOptions.factory.call(module.exports, module, module.exports, execOptions.require);"
  1266. ])
  1267. : runtimeRequirements.has(RuntimeGlobals.thisAsExports)
  1268. ? Template.asString([
  1269. `__webpack_modules__[moduleId].call(module.exports, module, module.exports, ${RuntimeGlobals.require});`
  1270. ])
  1271. : Template.asString([
  1272. `__webpack_modules__[moduleId](module, module.exports, ${RuntimeGlobals.require});`
  1273. ]);
  1274. const needModuleId = runtimeRequirements.has(RuntimeGlobals.moduleId);
  1275. const needModuleLoaded = runtimeRequirements.has(
  1276. RuntimeGlobals.moduleLoaded
  1277. );
  1278. const content = Template.asString([
  1279. "// Check if module is in cache",
  1280. "var cachedModule = __webpack_module_cache__[moduleId];",
  1281. "if (cachedModule !== undefined) {",
  1282. outputOptions.strictModuleErrorHandling
  1283. ? Template.indent([
  1284. "if (cachedModule.error !== undefined) throw cachedModule.error;",
  1285. "return cachedModule.exports;"
  1286. ])
  1287. : Template.indent("return cachedModule.exports;"),
  1288. "}",
  1289. "// Create a new module (and put it into the cache)",
  1290. "var module = __webpack_module_cache__[moduleId] = {",
  1291. Template.indent([
  1292. needModuleId ? "id: moduleId," : "// no module.id needed",
  1293. needModuleLoaded ? "loaded: false," : "// no module.loaded needed",
  1294. "exports: {}"
  1295. ]),
  1296. "};",
  1297. "",
  1298. outputOptions.strictModuleExceptionHandling
  1299. ? Template.asString([
  1300. "// Execute the module function",
  1301. "var threw = true;",
  1302. "try {",
  1303. Template.indent([moduleExecution, "threw = false;"]),
  1304. "} finally {",
  1305. Template.indent([
  1306. "if(threw) delete __webpack_module_cache__[moduleId];"
  1307. ]),
  1308. "}"
  1309. ])
  1310. : outputOptions.strictModuleErrorHandling
  1311. ? Template.asString([
  1312. "// Execute the module function",
  1313. "try {",
  1314. Template.indent(moduleExecution),
  1315. "} catch(e) {",
  1316. Template.indent(["module.error = e;", "throw e;"]),
  1317. "}"
  1318. ])
  1319. : Template.asString([
  1320. "// Execute the module function",
  1321. moduleExecution
  1322. ]),
  1323. needModuleLoaded
  1324. ? Template.asString([
  1325. "",
  1326. "// Flag the module as loaded",
  1327. `${RuntimeGlobals.moduleLoaded} = true;`,
  1328. ""
  1329. ])
  1330. : "",
  1331. "// Return the exports of the module",
  1332. "return module.exports;"
  1333. ]);
  1334. return tryRunOrWebpackError(
  1335. () => hooks.renderRequire.call(content, renderContext),
  1336. "JavascriptModulesPlugin.getCompilationHooks().renderRequire"
  1337. );
  1338. }
  1339. /**
  1340. * @param {Module[]} allModules allModules
  1341. * @param {MainRenderContext} renderContext renderContext
  1342. * @param {Set<Module>} inlinedModules inlinedModules
  1343. * @param {ChunkRenderContext} chunkRenderContext chunkRenderContext
  1344. * @param {CompilationHooks} hooks hooks
  1345. * @returns {Map<Module, Source>} renamed inlined modules
  1346. */
  1347. renameInlineModule(
  1348. allModules,
  1349. renderContext,
  1350. inlinedModules,
  1351. chunkRenderContext,
  1352. hooks
  1353. ) {
  1354. const { runtimeTemplate } = renderContext;
  1355. /** @type {Map<Module, { source: Source, ast: any, variables: Set<Variable>, usedInNonInlined: Set<Variable>}>} */
  1356. const inlinedModulesToInfo = new Map();
  1357. /** @type {Set<string>} */
  1358. const nonInlinedModuleThroughIdentifiers = new Set();
  1359. /** @type {Map<Module, Source>} */
  1360. const renamedInlinedModules = new Map();
  1361. for (const m of allModules) {
  1362. const isInlinedModule = inlinedModules && inlinedModules.has(m);
  1363. const moduleSource = this.renderModule(
  1364. m,
  1365. chunkRenderContext,
  1366. hooks,
  1367. isInlinedModule ? false : true
  1368. );
  1369. if (!moduleSource) continue;
  1370. const code = /** @type {string} */ (moduleSource.source());
  1371. const ast = JavascriptParser._parse(code, {
  1372. sourceType: "auto"
  1373. });
  1374. const scopeManager = eslintScope.analyze(ast, {
  1375. ecmaVersion: 6,
  1376. sourceType: "module",
  1377. optimistic: true,
  1378. ignoreEval: true
  1379. });
  1380. const globalScope = scopeManager.acquire(ast);
  1381. if (inlinedModules && inlinedModules.has(m)) {
  1382. const moduleScope = globalScope.childScopes[0];
  1383. inlinedModulesToInfo.set(m, {
  1384. source: moduleSource,
  1385. ast,
  1386. variables: new Set(moduleScope.variables),
  1387. usedInNonInlined: new Set()
  1388. });
  1389. } else {
  1390. for (const ref of globalScope.through) {
  1391. nonInlinedModuleThroughIdentifiers.add(ref.identifier.name);
  1392. }
  1393. }
  1394. }
  1395. for (const [, { variables, usedInNonInlined }] of inlinedModulesToInfo) {
  1396. for (const variable of variables) {
  1397. if (nonInlinedModuleThroughIdentifiers.has(variable.name)) {
  1398. usedInNonInlined.add(variable);
  1399. }
  1400. }
  1401. }
  1402. for (const [m, moduleInfo] of inlinedModulesToInfo) {
  1403. const { ast, source: _source, usedInNonInlined } = moduleInfo;
  1404. const source = new ReplaceSource(_source);
  1405. if (usedInNonInlined.size === 0) {
  1406. renamedInlinedModules.set(m, source);
  1407. continue;
  1408. }
  1409. const usedNames = new Set(
  1410. Array.from(inlinedModulesToInfo.get(m).variables).map(v => v.name)
  1411. );
  1412. for (const variable of usedInNonInlined) {
  1413. const references = getAllReferences(variable);
  1414. const allIdentifiers = new Set(
  1415. references.map(r => r.identifier).concat(variable.identifiers)
  1416. );
  1417. const newName = this.findNewName(
  1418. variable.name,
  1419. usedNames,
  1420. m.readableIdentifier(runtimeTemplate.requestShortener)
  1421. );
  1422. usedNames.add(newName);
  1423. for (const identifier of allIdentifiers) {
  1424. const r = identifier.range;
  1425. const path = getPathInAst(ast, identifier);
  1426. if (path && path.length > 1) {
  1427. const maybeProperty =
  1428. path[1].type === "AssignmentPattern" && path[1].left === path[0]
  1429. ? path[2]
  1430. : path[1];
  1431. if (maybeProperty.type === "Property" && maybeProperty.shorthand) {
  1432. source.insert(r[1], `: ${newName}`);
  1433. continue;
  1434. }
  1435. }
  1436. source.replace(r[0], r[1] - 1, newName);
  1437. }
  1438. }
  1439. renamedInlinedModules.set(m, source);
  1440. }
  1441. return renamedInlinedModules;
  1442. }
  1443. /**
  1444. * @param {string} oldName oldName
  1445. * @param {Set<string>} usedName usedName
  1446. * @param {string} extraInfo extraInfo
  1447. * @returns {string} extraInfo
  1448. */
  1449. findNewName(oldName, usedName, extraInfo) {
  1450. let name = oldName;
  1451. // Remove uncool stuff
  1452. extraInfo = extraInfo.replace(
  1453. /\.+\/|(\/index)?\.([a-zA-Z0-9]{1,4})($|\s|\?)|\s*\+\s*\d+\s*modules/g,
  1454. ""
  1455. );
  1456. const splittedInfo = extraInfo.split("/");
  1457. while (splittedInfo.length) {
  1458. name = splittedInfo.pop() + (name ? "_" + name : "");
  1459. const nameIdent = Template.toIdentifier(name);
  1460. if (!usedName.has(nameIdent)) {
  1461. return nameIdent;
  1462. }
  1463. }
  1464. let i = 0;
  1465. let nameWithNumber = Template.toIdentifier(`${name}_${i}`);
  1466. while (usedName.has(nameWithNumber)) {
  1467. i++;
  1468. nameWithNumber = Template.toIdentifier(`${name}_${i}`);
  1469. }
  1470. return nameWithNumber;
  1471. }
  1472. }
  1473. module.exports = JavascriptModulesPlugin;
  1474. module.exports.chunkHasJs = chunkHasJs;