ArrayPushCallbackChunkFormatPlugin.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. /** @typedef {import("../Compiler")} Compiler */
  16. /** @typedef {import("../ChunkGraph").EntryModuleWithChunkGroup} EntryModuleWithChunkGroup */
  17. const PLUGIN_NAME = "ArrayPushCallbackChunkFormatPlugin";
  18. class ArrayPushCallbackChunkFormatPlugin {
  19. /**
  20. * Apply the plugin
  21. * @param {Compiler} compiler the compiler instance
  22. * @returns {void}
  23. */
  24. apply(compiler) {
  25. compiler.hooks.thisCompilation.tap(PLUGIN_NAME, compilation => {
  26. compilation.hooks.additionalChunkRuntimeRequirements.tap(
  27. PLUGIN_NAME,
  28. (chunk, set, { chunkGraph }) => {
  29. if (chunk.hasRuntime()) return;
  30. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
  31. set.add(RuntimeGlobals.onChunksLoaded);
  32. set.add(RuntimeGlobals.exports);
  33. set.add(RuntimeGlobals.require);
  34. }
  35. set.add(RuntimeGlobals.chunkCallback);
  36. }
  37. );
  38. const hooks = getCompilationHooks(compilation);
  39. hooks.renderChunk.tap(PLUGIN_NAME, (modules, renderContext) => {
  40. const { chunk, chunkGraph, runtimeTemplate } = renderContext;
  41. const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
  42. const globalObject = runtimeTemplate.globalObject;
  43. const source = new ConcatSource();
  44. const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
  45. if (hotUpdateChunk) {
  46. const hotUpdateGlobal = runtimeTemplate.outputOptions.hotUpdateGlobal;
  47. source.add(`${globalObject}[${JSON.stringify(hotUpdateGlobal)}](`);
  48. source.add(`${JSON.stringify(chunk.id)},`);
  49. source.add(modules);
  50. if (runtimeModules.length > 0) {
  51. source.add(",\n");
  52. const runtimePart = Template.renderChunkRuntimeModules(
  53. runtimeModules,
  54. renderContext
  55. );
  56. source.add(runtimePart);
  57. }
  58. source.add(")");
  59. } else {
  60. const chunkLoadingGlobal =
  61. runtimeTemplate.outputOptions.chunkLoadingGlobal;
  62. source.add(
  63. `(${globalObject}[${JSON.stringify(
  64. chunkLoadingGlobal
  65. )}] = ${globalObject}[${JSON.stringify(
  66. chunkLoadingGlobal
  67. )}] || []).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: compilation.codeGenerationResults
  88. })
  89. );
  90. }
  91. if (entries.length > 0) {
  92. const startupSource = new RawSource(
  93. generateEntryStartup(
  94. chunkGraph,
  95. runtimeTemplate,
  96. entries,
  97. chunk,
  98. true
  99. )
  100. );
  101. runtime.add(
  102. hooks.renderStartup.call(
  103. startupSource,
  104. entries[entries.length - 1][0],
  105. {
  106. ...renderContext,
  107. inlined: false
  108. }
  109. )
  110. );
  111. if (
  112. chunkGraph
  113. .getChunkRuntimeRequirements(chunk)
  114. .has(RuntimeGlobals.returnExportsFromRuntime)
  115. ) {
  116. runtime.add(`return ${RuntimeGlobals.exports};\n`);
  117. }
  118. }
  119. runtime.add("}\n");
  120. source.add(",\n");
  121. source.add(new PrefixSource("/******/ ", runtime));
  122. }
  123. source.add("])");
  124. }
  125. return source;
  126. });
  127. hooks.chunkHash.tap(
  128. PLUGIN_NAME,
  129. (chunk, hash, { chunkGraph, runtimeTemplate }) => {
  130. if (chunk.hasRuntime()) return;
  131. hash.update(
  132. `${PLUGIN_NAME}1${runtimeTemplate.outputOptions.chunkLoadingGlobal}${runtimeTemplate.outputOptions.hotUpdateGlobal}${runtimeTemplate.globalObject}`
  133. );
  134. /** @type {EntryModuleWithChunkGroup[]} */
  135. const entries = [
  136. ...chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
  137. ];
  138. updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
  139. }
  140. );
  141. });
  142. }
  143. }
  144. module.exports = ArrayPushCallbackChunkFormatPlugin;