ChunkPrefetchPreloadPlugin.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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 lazyModule = require("../util/lazyModule");
  8. /** @import Compiler from "../Compiler" */
  9. // only a chunk graph carrying a prefetch/preload relation emits these
  10. const getChunkPrefetchFunctionRuntimeModule = lazyModule(() =>
  11. require("./ChunkPrefetchFunctionRuntimeModule")
  12. );
  13. const getChunkPrefetchStartupRuntimeModule = lazyModule(() =>
  14. require("./ChunkPrefetchStartupRuntimeModule")
  15. );
  16. const getChunkPrefetchTriggerRuntimeModule = lazyModule(() =>
  17. require("./ChunkPrefetchTriggerRuntimeModule")
  18. );
  19. const getChunkPreloadTriggerRuntimeModule = lazyModule(() =>
  20. require("./ChunkPreloadTriggerRuntimeModule")
  21. );
  22. const PLUGIN_NAME = "ChunkPrefetchPreloadPlugin";
  23. /**
  24. * Adds runtime support for chunk prefetch and preload relationships discovered
  25. * in the chunk graph.
  26. */
  27. class ChunkPrefetchPreloadPlugin {
  28. /**
  29. * Registers compilation hooks that emit the runtime modules responsible for
  30. * scheduling chunk prefetch and preload requests.
  31. * @param {Compiler} compiler the compiler
  32. * @returns {void}
  33. */
  34. apply(compiler) {
  35. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
  36. compilation.hooks.additionalChunkRuntimeRequirements.tap(
  37. PLUGIN_NAME,
  38. (chunk, set, { chunkGraph }) => {
  39. if (chunkGraph.getNumberOfEntryModules(chunk) === 0) return;
  40. const startupChildChunks = chunk.getChildrenOfTypeInOrder(
  41. chunkGraph,
  42. "prefetchOrder"
  43. );
  44. if (startupChildChunks) {
  45. set.add(RuntimeGlobals.prefetchChunk);
  46. set.add(RuntimeGlobals.onChunksLoaded);
  47. set.add(RuntimeGlobals.exports);
  48. compilation.addLazyRuntimeModule(
  49. chunk,
  50. getChunkPrefetchStartupRuntimeModule,
  51. (Ctor) => new Ctor(startupChildChunks)
  52. );
  53. }
  54. }
  55. );
  56. compilation.hooks.additionalTreeRuntimeRequirements.tap(
  57. PLUGIN_NAME,
  58. (chunk, set, { chunkGraph }) => {
  59. const chunkMap = chunk.getChildIdsByOrdersMap(chunkGraph);
  60. if (chunkMap.prefetch) {
  61. set.add(RuntimeGlobals.prefetchChunk);
  62. compilation.addLazyRuntimeModule(
  63. chunk,
  64. getChunkPrefetchTriggerRuntimeModule,
  65. (Ctor) => new Ctor(chunkMap.prefetch)
  66. );
  67. }
  68. if (chunkMap.preload) {
  69. set.add(RuntimeGlobals.preloadChunk);
  70. compilation.addLazyRuntimeModule(
  71. chunk,
  72. getChunkPreloadTriggerRuntimeModule,
  73. (Ctor) => new Ctor(chunkMap.preload)
  74. );
  75. }
  76. if (chunkMap.cssPreload) {
  77. // CSS-only preload (`parser.javascript.dynamicImportCssPreload`):
  78. // the trigger reaches the CSS `.s` handler itself
  79. // (`<link rel="preload" as="style">`), so it asks for the handlers
  80. // alone — nothing here calls the one that fans out over them.
  81. set.add(RuntimeGlobals.preloadChunkHandlers);
  82. compilation.addLazyRuntimeModule(
  83. chunk,
  84. getChunkPreloadTriggerRuntimeModule,
  85. (Ctor) => new Ctor(chunkMap.cssPreload, "cssPreload")
  86. );
  87. }
  88. }
  89. );
  90. // The handlers object is what carries the runtime module, so a chunk asking
  91. // only for it — a trigger that reaches one handler by name — ships no
  92. // fan-out function. Whether one is wanted is read here rather than in
  93. // `create`, which runs after the requirement pass is over.
  94. for (const [type, fn, handlers] of /** @type {const} */ ([
  95. [
  96. "prefetch",
  97. RuntimeGlobals.prefetchChunk,
  98. RuntimeGlobals.prefetchChunkHandlers
  99. ],
  100. [
  101. "preload",
  102. RuntimeGlobals.preloadChunk,
  103. RuntimeGlobals.preloadChunkHandlers
  104. ]
  105. ])) {
  106. compilation.hooks.runtimeRequirementInTree
  107. .for(fn)
  108. .tap(PLUGIN_NAME, (chunk, set) => {
  109. set.add(handlers);
  110. });
  111. compilation.hooks.runtimeRequirementInTree
  112. .for(handlers)
  113. .tap(PLUGIN_NAME, (chunk, set) => {
  114. const runtimeFunction = set.has(fn) ? fn : null;
  115. compilation.addLazyRuntimeModule(
  116. chunk,
  117. getChunkPrefetchFunctionRuntimeModule,
  118. (Ctor) => new Ctor(type, runtimeFunction, handlers)
  119. );
  120. });
  121. }
  122. });
  123. }
  124. }
  125. module.exports = ChunkPrefetchPreloadPlugin;