ArrayPushCallbackChunkFormatPlugin.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { ConcatSource, PrefixSource, RawSource } = require("webpack-sources");
  7. const { RuntimeGlobals } = require("..");
  8. const HotUpdateChunk = require("../HotUpdateChunk");
  9. const Template = require("../Template");
  10. const { getCompilationHooks } = require("./JavascriptModulesPlugin");
  11. const {
  12. generateEntryStartup,
  13. updateHashForEntryStartup
  14. } = require("./StartupHelpers");
  15. /** @import Compiler from "../Compiler" */
  16. /** @import { EntryModuleWithChunkGroup } from "../ChunkGraph" */
  17. /** @import CodeGenerationResults from "../CodeGenerationResults" */
  18. const PLUGIN_NAME = "ArrayPushCallbackChunkFormatPlugin";
  19. class ArrayPushCallbackChunkFormatPlugin {
  20. /**
  21. * Applies the plugin by registering its hooks on the compiler.
  22. * @param {Compiler} compiler the compiler instance
  23. * @returns {void}
  24. */
  25. apply(compiler) {
  26. compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
  27. compilation.hooks.additionalChunkRuntimeRequirements.tap(
  28. PLUGIN_NAME,
  29. (chunk, set, { chunkGraph }) => {
  30. if (chunk.hasRuntime()) return;
  31. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
  32. set.add(RuntimeGlobals.onChunksLoaded);
  33. set.add(RuntimeGlobals.exports);
  34. set.add(RuntimeGlobals.require);
  35. }
  36. set.add(RuntimeGlobals.chunkCallback);
  37. }
  38. );
  39. const hooks = getCompilationHooks(compilation);
  40. hooks.renderChunk.tap(PLUGIN_NAME, (modules, renderContext) => {
  41. const { chunk, chunkGraph, runtimeTemplate } = renderContext;
  42. const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
  43. const globalObject = runtimeTemplate.globalObject;
  44. const source = new ConcatSource();
  45. const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
  46. if (hotUpdateChunk) {
  47. const hotUpdateGlobal = runtimeTemplate.outputOptions.hotUpdateGlobal;
  48. source.add(`${globalObject}[${JSON.stringify(hotUpdateGlobal)}](`);
  49. source.add(`${JSON.stringify(chunk.id)},`);
  50. source.add(modules);
  51. if (runtimeModules.length > 0) {
  52. source.add(",\n");
  53. const runtimePart = Template.renderChunkRuntimeModules(
  54. runtimeModules,
  55. renderContext
  56. );
  57. source.add(runtimePart);
  58. }
  59. source.add(")");
  60. } else {
  61. const chunkLoadingGlobal =
  62. runtimeTemplate.outputOptions.chunkLoadingGlobal;
  63. const chunkLoadingGlobalExpr = `${globalObject}[${JSON.stringify(
  64. chunkLoadingGlobal
  65. )}]`;
  66. source.add(
  67. `(${runtimeTemplate.assignOr(chunkLoadingGlobalExpr, "[]")}).push([`
  68. );
  69. source.add(`${JSON.stringify(chunk.ids)},`);
  70. source.add(modules);
  71. /** @type {EntryModuleWithChunkGroup[]} */
  72. const entries = [
  73. ...chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
  74. ];
  75. if (runtimeModules.length > 0 || entries.length > 0) {
  76. const runtime = new ConcatSource(
  77. `${
  78. runtimeTemplate.supportsArrowFunction()
  79. ? `${RuntimeGlobals.require} =>`
  80. : `function(${RuntimeGlobals.require})`
  81. } { // webpackRuntimeModules\n`
  82. );
  83. if (runtimeModules.length > 0) {
  84. runtime.add(
  85. Template.renderRuntimeModules(runtimeModules, {
  86. ...renderContext,
  87. codeGenerationResults:
  88. /** @type {CodeGenerationResults} */
  89. (compilation.codeGenerationResults)
  90. })
  91. );
  92. }
  93. if (entries.length > 0) {
  94. const startupSource = new RawSource(
  95. generateEntryStartup(
  96. chunkGraph,
  97. runtimeTemplate,
  98. entries,
  99. chunk,
  100. true
  101. )
  102. );
  103. runtime.add(
  104. hooks.renderStartup.call(
  105. startupSource,
  106. entries[entries.length - 1][0],
  107. renderContext
  108. )
  109. );
  110. if (
  111. chunkGraph
  112. .getChunkRuntimeRequirements(chunk)
  113. .has(RuntimeGlobals.returnExportsFromRuntime)
  114. ) {
  115. runtime.add(`return ${RuntimeGlobals.exports};\n`);
  116. }
  117. }
  118. runtime.add("}\n");
  119. source.add(",\n");
  120. source.add(new PrefixSource("/******/ ", runtime));
  121. }
  122. source.add("])");
  123. }
  124. return source;
  125. });
  126. hooks.chunkHash.tap(
  127. PLUGIN_NAME,
  128. (chunk, hash, { chunkGraph, runtimeTemplate }) => {
  129. if (chunk.hasRuntime()) return;
  130. hash.update(
  131. `${PLUGIN_NAME}1${runtimeTemplate.outputOptions.chunkLoadingGlobal}${runtimeTemplate.outputOptions.hotUpdateGlobal}${runtimeTemplate.globalObject}`
  132. );
  133. /** @type {EntryModuleWithChunkGroup[]} */
  134. const entries = [
  135. ...chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
  136. ];
  137. updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
  138. }
  139. );
  140. });
  141. }
  142. }
  143. module.exports = ArrayPushCallbackChunkFormatPlugin;