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. class EnsureChunkConditionsPlugin {
  11. /**
  12. * Apply the plugin
  13. * @param {Compiler} compiler the compiler instance
  14. * @returns {void}
  15. */
  16. apply(compiler) {
  17. compiler.hooks.compilation.tap(
  18. "EnsureChunkConditionsPlugin",
  19. compilation => {
  20. /**
  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: "EnsureChunkConditionsPlugin",
  76. stage: STAGE_BASIC
  77. },
  78. handler
  79. );
  80. }
  81. );
  82. }
  83. }
  84. module.exports = EnsureChunkConditionsPlugin;