EnsureChunkConditionsPlugin.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { STAGE_BASIC } = require("../OptimizationStages");
  7. /** @typedef {import("../Chunk")} Chunk */
  8. /** @typedef {import("../ChunkGroup")} ChunkGroup */
  9. /** @typedef {import("../Compiler")} Compiler */
  10. const PLUGIN_NAME = "EnsureChunkConditionsPlugin";
  11. class EnsureChunkConditionsPlugin {
  12. /**
  13. * Applies the plugin by registering its hooks on the compiler.
  14. * @param {Compiler} compiler the compiler instance
  15. * @returns {void}
  16. */
  17. apply(compiler) {
  18. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
  19. /**
  20. * Handles the hook callback for this code path.
  21. * @param {Iterable<Chunk>} chunks the chunks
  22. */
  23. const handler = (chunks) => {
  24. const chunkGraph = compilation.chunkGraph;
  25. // These sets are hoisted here to save memory
  26. // They are cleared at the end of every loop
  27. /** @type {Set<Chunk>} */
  28. const sourceChunks = new Set();
  29. /** @type {Set<ChunkGroup>} */
  30. const chunkGroups = new Set();
  31. for (const module of compilation.modules) {
  32. if (!module.hasChunkCondition()) continue;
  33. for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
  34. if (!module.chunkCondition(chunk, compilation)) {
  35. sourceChunks.add(chunk);
  36. for (const group of chunk.groupsIterable) {
  37. chunkGroups.add(group);
  38. }
  39. }
  40. }
  41. if (sourceChunks.size === 0) continue;
  42. /** @type {Set<Chunk>} */
  43. const targetChunks = new Set();
  44. chunkGroupLoop: for (const chunkGroup of chunkGroups) {
  45. // Can module be placed in a chunk of this group?
  46. for (const chunk of chunkGroup.chunks) {
  47. if (module.chunkCondition(chunk, compilation)) {
  48. targetChunks.add(chunk);
  49. continue chunkGroupLoop;
  50. }
  51. }
  52. // We reached the entrypoint: fail
  53. if (chunkGroup.isInitial()) {
  54. throw new Error(
  55. `Cannot fulfil chunk condition of ${module.identifier()}`
  56. );
  57. }
  58. // Try placing in all parents
  59. for (const group of chunkGroup.parentsIterable) {
  60. chunkGroups.add(group);
  61. }
  62. }
  63. for (const sourceChunk of sourceChunks) {
  64. chunkGraph.disconnectChunkAndModule(sourceChunk, module);
  65. }
  66. for (const targetChunk of targetChunks) {
  67. chunkGraph.connectChunkAndModule(targetChunk, module);
  68. }
  69. sourceChunks.clear();
  70. chunkGroups.clear();
  71. }
  72. };
  73. compilation.hooks.optimizeChunks.tap(
  74. {
  75. name: PLUGIN_NAME,
  76. stage: STAGE_BASIC
  77. },
  78. handler
  79. );
  80. });
  81. }
  82. }
  83. module.exports = EnsureChunkConditionsPlugin;