ImportScriptsChunkLoadingPlugin.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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 StartupChunkDependenciesPlugin = require("../runtime/StartupChunkDependenciesPlugin");
  8. const lazyModule = require("../util/lazyModule");
  9. /** @import Chunk from "../Chunk" */
  10. /** @import Compiler from "../Compiler" */
  11. /** @import { RuntimeRequirements } from "../Module" */
  12. // only a chunk that loads other chunks at runtime emits this
  13. const getImportScriptsChunkLoadingRuntimeModule = lazyModule(() =>
  14. require("./ImportScriptsChunkLoadingRuntimeModule")
  15. );
  16. const PLUGIN_NAME = "ImportScriptsChunkLoadingPlugin";
  17. /**
  18. * Enables worker-side chunk loading via `importScripts` and wires in the
  19. * runtime helpers needed for startup, loading, and hot updates.
  20. */
  21. class ImportScriptsChunkLoadingPlugin {
  22. /**
  23. * Registers compilation hooks that attach the `importScripts` chunk-loading
  24. * runtime and its supporting globals to chunks using that backend.
  25. * @param {Compiler} compiler the compiler instance
  26. * @returns {void}
  27. */
  28. apply(compiler) {
  29. new StartupChunkDependenciesPlugin({
  30. chunkLoading: "import-scripts",
  31. asyncChunkLoading: true
  32. }).apply(compiler);
  33. compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
  34. const globalChunkLoading = compilation.outputOptions.chunkLoading;
  35. /**
  36. * Determines whether the chunk resolves additional chunks through the
  37. * worker-side `importScripts` backend.
  38. * @param {Chunk} chunk chunk
  39. * @returns {boolean} true, if wasm loading is enabled for the chunk
  40. */
  41. const isEnabledForChunk = (chunk) => {
  42. const options = chunk.getEntryOptions();
  43. const chunkLoading =
  44. options && options.chunkLoading !== undefined
  45. ? options.chunkLoading
  46. : globalChunkLoading;
  47. return chunkLoading === "import-scripts";
  48. };
  49. /** @type {WeakSet<Chunk>} */
  50. const onceForChunkSet = new WeakSet();
  51. /**
  52. * Adds the `importScripts` chunk-loading runtime module to a chunk once
  53. * and records the globals it depends on.
  54. * @param {Chunk} chunk chunk
  55. * @param {RuntimeRequirements} set runtime requirements
  56. */
  57. const handler = (chunk, set) => {
  58. if (onceForChunkSet.has(chunk)) return;
  59. onceForChunkSet.add(chunk);
  60. if (!isEnabledForChunk(chunk)) return;
  61. const withCreateScriptUrl = Boolean(
  62. compilation.outputOptions.trustedTypes
  63. );
  64. compilation.addLazyRuntimeModule(
  65. chunk,
  66. getImportScriptsChunkLoadingRuntimeModule,
  67. (Ctor) => new Ctor(set, withCreateScriptUrl)
  68. );
  69. };
  70. /**
  71. * Installing a chunk is the only part that writes the module factories and
  72. * looks a chunk id up; a base uri or `onChunksLoaded` comes without either.
  73. * Kept off `handler`, which runs once per chunk and so cannot see which of the
  74. * requirements below the chunk ends up with.
  75. * @param {Chunk} chunk chunk
  76. * @param {RuntimeRequirements} set runtime requirements
  77. */
  78. const installHandler = (chunk, set) => {
  79. if (!isEnabledForChunk(chunk)) return;
  80. set.add(RuntimeGlobals.moduleFactoriesAddOnly);
  81. set.add(RuntimeGlobals.hasOwnProperty);
  82. };
  83. for (const requirement of [
  84. RuntimeGlobals.ensureChunkHandlers,
  85. RuntimeGlobals.hmrDownloadUpdateHandlers,
  86. RuntimeGlobals.hmrDownloadManifest,
  87. RuntimeGlobals.baseURI,
  88. RuntimeGlobals.onChunksLoaded
  89. ]) {
  90. compilation.hooks.runtimeRequirementInTree
  91. .for(requirement)
  92. .tap(PLUGIN_NAME, handler);
  93. }
  94. for (const requirement of [
  95. RuntimeGlobals.ensureChunkHandlers,
  96. RuntimeGlobals.chunkCallback,
  97. RuntimeGlobals.hmrDownloadUpdateHandlers
  98. ]) {
  99. compilation.hooks.runtimeRequirementInTree
  100. .for(requirement)
  101. .tap(PLUGIN_NAME, installHandler);
  102. }
  103. // Both `importScripts` calls the module emits — loading a chunk and loading a
  104. // hot update — are wrapped under trusted types.
  105. for (const requirement of [
  106. RuntimeGlobals.ensureChunkHandlers,
  107. RuntimeGlobals.hmrDownloadUpdateHandlers
  108. ]) {
  109. compilation.hooks.runtimeRequirementInTree
  110. .for(requirement)
  111. .tap(PLUGIN_NAME, (chunk, set) => {
  112. if (!isEnabledForChunk(chunk)) return;
  113. if (compilation.outputOptions.trustedTypes) {
  114. set.add(RuntimeGlobals.createScriptUrl);
  115. }
  116. });
  117. }
  118. compilation.hooks.runtimeRequirementInTree
  119. .for(RuntimeGlobals.ensureChunkHandlers)
  120. .tap(PLUGIN_NAME, (chunk, set) => {
  121. if (!isEnabledForChunk(chunk)) return;
  122. set.add(RuntimeGlobals.publicPath);
  123. set.add(RuntimeGlobals.getChunkScriptFilename);
  124. });
  125. compilation.hooks.runtimeRequirementInTree
  126. .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
  127. .tap(PLUGIN_NAME, (chunk, set) => {
  128. if (!isEnabledForChunk(chunk)) return;
  129. set.add(RuntimeGlobals.publicPath);
  130. set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
  131. set.add(RuntimeGlobals.moduleCache);
  132. set.add(RuntimeGlobals.hmrModuleData);
  133. set.add(RuntimeGlobals.moduleFactoriesAddOnly);
  134. });
  135. compilation.hooks.runtimeRequirementInTree
  136. .for(RuntimeGlobals.hmrDownloadManifest)
  137. .tap(PLUGIN_NAME, (chunk, set) => {
  138. if (!isEnabledForChunk(chunk)) return;
  139. set.add(RuntimeGlobals.publicPath);
  140. set.add(RuntimeGlobals.getUpdateManifestFilename);
  141. });
  142. });
  143. }
  144. }
  145. module.exports = ImportScriptsChunkLoadingPlugin;