JavascriptModulesPlugin.js 52 KB

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