EnsureChunkConditionsPlugin.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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. * Apply the plugin
  14. * @param {Compiler} compiler the compiler instance
  15. * @returns {void}
  16. */
  17. apply(compiler) {
  18. compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
  19. /**
  20. * @param {Iterable<Chunk>} chunks the chunks
  21. */
  22. const handler = chunks => {
  23. const chunkGraph = compilation.chunkGraph;
  24. // These sets are hoisted here to save memory
  25. // They are cleared at the end of every loop
  26. /** @type {Set<Chunk>} */
  27. const sourceChunks = new Set();
  28. /** @type {Set<ChunkGroup>} */
  29. const chunkGroups = new Set();
  30. for (const module of compilation.modules) {
  31. if (!module.hasChunkCondition()) continue;
  32. for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
  33. if (!module.chunkCondition(chunk, compilation)) {
  34. sourceChunks.add(chunk);
  35. for (const group of chunk.groupsIterable) {
  36. chunkGroups.add(group);
  37. }
  38. }
  39. }
  40. if (sourceChunks.size === 0) continue;
  41. /** @type {Set<Chunk>} */
  42. const targetChunks = new Set();
  43. chunkGroupLoop: for (const chunkGroup of chunkGroups) {
  44. // Can module be placed in a chunk of this group?
  45. for (const chunk of chunkGroup.chunks) {
  46. if (module.chunkCondition(chunk, compilation)) {
  47. targetChunks.add(chunk);
  48. continue chunkGroupLoop;
  49. }
  50. }
  51. // We reached the entrypoint: fail
  52. if (chunkGroup.isInitial()) {
  53. throw new Error(
  54. `Cannot fulfil chunk condition of ${module.identifier()}`
  55. );
  56. }
  57. // Try placing in all parents
  58. for (const group of chunkGroup.parentsIterable) {
  59. chunkGroups.add(group);
  60. }
  61. }
  62. for (const sourceChunk of sourceChunks) {
  63. chunkGraph.disconnectChunkAndModule(sourceChunk, module);
  64. }
  65. for (const targetChunk of targetChunks) {
  66. chunkGraph.connectChunkAndModule(targetChunk, module);
  67. }
  68. sourceChunks.clear();
  69. chunkGroups.clear();
  70. }
  71. };
  72. compilation.hooks.optimizeChunks.tap(
  73. {
  74. name: PLUGIN_NAME,
  75. stage: STAGE_BASIC
  76. },
  77. handler
  78. );
  79. });
  80. }
  81. }
  82. module.exports = EnsureChunkConditionsPlugin;