ModuleChunkLoadingPlugin.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RuntimeGlobals = require("../RuntimeGlobals");
  7. const ExportWebpackRequireRuntimeModule = require("./ExportWebpackRequireRuntimeModule");
  8. const ModuleChunkLoadingRuntimeModule = require("./ModuleChunkLoadingRuntimeModule");
  9. /** @typedef {import("../Chunk")} Chunk */
  10. /** @typedef {import("../Compiler")} Compiler */
  11. /** @typedef {import("../Module").RuntimeRequirements} RuntimeRequirements */
  12. const PLUGIN_NAME = "ModuleChunkLoadingPlugin";
  13. class ModuleChunkLoadingPlugin {
  14. /**
  15. * Applies the plugin by registering its hooks on the compiler.
  16. * @param {Compiler} compiler the compiler instance
  17. * @returns {void}
  18. */
  19. apply(compiler) {
  20. compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
  21. const globalChunkLoading = compilation.outputOptions.chunkLoading;
  22. /**
  23. * Checks whether this module chunk loading plugin is enabled for chunk.
  24. * @param {Chunk} chunk chunk to check
  25. * @returns {boolean} true, when the plugin is enabled for the chunk
  26. */
  27. const isEnabledForChunk = (chunk) => {
  28. const options = chunk.getEntryOptions();
  29. const chunkLoading =
  30. options && options.chunkLoading !== undefined
  31. ? options.chunkLoading
  32. : globalChunkLoading;
  33. return chunkLoading === "import";
  34. };
  35. /** @type {WeakSet<Chunk>} */
  36. const onceForChunkSet = new WeakSet();
  37. /**
  38. * Handles the hook callback for this code path.
  39. * @param {Chunk} chunk chunk to check
  40. * @param {RuntimeRequirements} set runtime requirements
  41. */
  42. const handler = (chunk, set) => {
  43. if (onceForChunkSet.has(chunk)) return;
  44. onceForChunkSet.add(chunk);
  45. if (!isEnabledForChunk(chunk)) return;
  46. set.add(RuntimeGlobals.moduleFactoriesAddOnly);
  47. set.add(RuntimeGlobals.hasOwnProperty);
  48. compilation.addRuntimeModule(
  49. chunk,
  50. new ModuleChunkLoadingRuntimeModule(set)
  51. );
  52. };
  53. compilation.hooks.runtimeRequirementInTree
  54. .for(RuntimeGlobals.ensureChunkHandlers)
  55. .tap(PLUGIN_NAME, handler);
  56. compilation.hooks.runtimeRequirementInTree
  57. .for(RuntimeGlobals.baseURI)
  58. .tap(PLUGIN_NAME, handler);
  59. compilation.hooks.runtimeRequirementInTree
  60. .for(RuntimeGlobals.externalInstallChunk)
  61. .tap(PLUGIN_NAME, handler);
  62. compilation.hooks.runtimeRequirementInTree
  63. .for(RuntimeGlobals.onChunksLoaded)
  64. .tap(PLUGIN_NAME, handler);
  65. compilation.hooks.runtimeRequirementInTree
  66. .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
  67. .tap(PLUGIN_NAME, handler);
  68. compilation.hooks.runtimeRequirementInTree
  69. .for(RuntimeGlobals.hmrDownloadManifest)
  70. .tap(PLUGIN_NAME, handler);
  71. compilation.hooks.runtimeRequirementInTree
  72. .for(RuntimeGlobals.externalInstallChunk)
  73. .tap(PLUGIN_NAME, (chunk) => {
  74. if (!isEnabledForChunk(chunk)) return;
  75. compilation.addRuntimeModule(
  76. chunk,
  77. new ExportWebpackRequireRuntimeModule()
  78. );
  79. });
  80. // We need public path only when we prefetch/preload chunk or public path is not `auto`
  81. compilation.hooks.runtimeRequirementInTree
  82. .for(RuntimeGlobals.prefetchChunkHandlers)
  83. .tap(PLUGIN_NAME, (chunk, set) => {
  84. if (!isEnabledForChunk(chunk)) return;
  85. set.add(RuntimeGlobals.publicPath);
  86. });
  87. compilation.hooks.runtimeRequirementInTree
  88. .for(RuntimeGlobals.preloadChunkHandlers)
  89. .tap(PLUGIN_NAME, (chunk, set) => {
  90. if (!isEnabledForChunk(chunk)) return;
  91. set.add(RuntimeGlobals.publicPath);
  92. });
  93. compilation.hooks.runtimeRequirementInTree
  94. .for(RuntimeGlobals.ensureChunkHandlers)
  95. .tap(PLUGIN_NAME, (chunk, set) => {
  96. if (!isEnabledForChunk(chunk)) return;
  97. if (compilation.outputOptions.publicPath !== "auto") {
  98. set.add(RuntimeGlobals.publicPath);
  99. }
  100. set.add(RuntimeGlobals.getChunkScriptFilename);
  101. });
  102. compilation.hooks.runtimeRequirementInTree
  103. .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
  104. .tap(PLUGIN_NAME, (chunk, set) => {
  105. if (!isEnabledForChunk(chunk)) return;
  106. set.add(RuntimeGlobals.publicPath);
  107. set.add(RuntimeGlobals.loadScript);
  108. set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
  109. set.add(RuntimeGlobals.moduleCache);
  110. set.add(RuntimeGlobals.hmrModuleData);
  111. set.add(RuntimeGlobals.moduleFactoriesAddOnly);
  112. });
  113. compilation.hooks.runtimeRequirementInTree
  114. .for(RuntimeGlobals.hmrDownloadManifest)
  115. .tap(PLUGIN_NAME, (chunk, set) => {
  116. if (!isEnabledForChunk(chunk)) return;
  117. set.add(RuntimeGlobals.publicPath);
  118. set.add(RuntimeGlobals.getUpdateManifestFilename);
  119. });
  120. compilation.hooks.additionalTreeRuntimeRequirements.tap(
  121. PLUGIN_NAME,
  122. (chunk, set, { chunkGraph }) => {
  123. if (chunkGraph.hasChunkEntryDependentChunks(chunk)) {
  124. set.add(RuntimeGlobals.externalInstallChunk);
  125. }
  126. }
  127. );
  128. });
  129. }
  130. }
  131. module.exports = ModuleChunkLoadingPlugin;