EnsureChunkConditionsPlugin.js 2.5 KB

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