You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FlagDependencyExportsPlugin.js 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const Queue = require("./util/Queue");
  7. const addToSet = (a, b) => {
  8. let changed = false;
  9. for (const item of b) {
  10. if (!a.has(item)) {
  11. a.add(item);
  12. changed = true;
  13. }
  14. }
  15. return changed;
  16. };
  17. class FlagDependencyExportsPlugin {
  18. apply(compiler) {
  19. compiler.hooks.compilation.tap(
  20. "FlagDependencyExportsPlugin",
  21. compilation => {
  22. compilation.hooks.finishModules.tap(
  23. "FlagDependencyExportsPlugin",
  24. modules => {
  25. const dependencies = new Map();
  26. const queue = new Queue();
  27. let module;
  28. let moduleWithExports;
  29. let moduleProvidedExports;
  30. let providedExportsAreTemporary;
  31. const processDependenciesBlock = depBlock => {
  32. for (const dep of depBlock.dependencies) {
  33. if (processDependency(dep)) return true;
  34. }
  35. for (const variable of depBlock.variables) {
  36. for (const dep of variable.dependencies) {
  37. if (processDependency(dep)) return true;
  38. }
  39. }
  40. for (const block of depBlock.blocks) {
  41. if (processDependenciesBlock(block)) return true;
  42. }
  43. return false;
  44. };
  45. const processDependency = dep => {
  46. const exportDesc = dep.getExports && dep.getExports();
  47. if (!exportDesc) return;
  48. moduleWithExports = true;
  49. const exports = exportDesc.exports;
  50. // break early if it's only in the worst state
  51. if (module.buildMeta.providedExports === true) {
  52. return true;
  53. }
  54. // break if it should move to the worst state
  55. if (exports === true) {
  56. module.buildMeta.providedExports = true;
  57. notifyDependencies();
  58. return true;
  59. }
  60. // merge in new exports
  61. if (Array.isArray(exports)) {
  62. if (addToSet(moduleProvidedExports, exports)) {
  63. notifyDependencies();
  64. }
  65. }
  66. // store dependencies
  67. const exportDeps = exportDesc.dependencies;
  68. if (exportDeps) {
  69. providedExportsAreTemporary = true;
  70. for (const exportDependency of exportDeps) {
  71. // add dependency for this module
  72. const set = dependencies.get(exportDependency);
  73. if (set === undefined) {
  74. dependencies.set(exportDependency, new Set([module]));
  75. } else {
  76. set.add(module);
  77. }
  78. }
  79. }
  80. return false;
  81. };
  82. const notifyDependencies = () => {
  83. const deps = dependencies.get(module);
  84. if (deps !== undefined) {
  85. for (const dep of deps) {
  86. queue.enqueue(dep);
  87. }
  88. }
  89. };
  90. // Start with all modules without provided exports
  91. for (const module of modules) {
  92. if (module.buildInfo.temporaryProvidedExports) {
  93. // Clear exports when they are temporary
  94. // and recreate them
  95. module.buildMeta.providedExports = null;
  96. queue.enqueue(module);
  97. } else if (!module.buildMeta.providedExports) {
  98. queue.enqueue(module);
  99. }
  100. }
  101. while (queue.length > 0) {
  102. module = queue.dequeue();
  103. if (module.buildMeta.providedExports !== true) {
  104. moduleWithExports =
  105. module.buildMeta && module.buildMeta.exportsType;
  106. moduleProvidedExports = Array.isArray(
  107. module.buildMeta.providedExports
  108. )
  109. ? new Set(module.buildMeta.providedExports)
  110. : new Set();
  111. providedExportsAreTemporary = false;
  112. processDependenciesBlock(module);
  113. module.buildInfo.temporaryProvidedExports = providedExportsAreTemporary;
  114. if (!moduleWithExports) {
  115. module.buildMeta.providedExports = true;
  116. notifyDependencies();
  117. } else if (module.buildMeta.providedExports !== true) {
  118. module.buildMeta.providedExports = Array.from(
  119. moduleProvidedExports
  120. );
  121. }
  122. }
  123. }
  124. }
  125. );
  126. const providedExportsCache = new WeakMap();
  127. compilation.hooks.rebuildModule.tap(
  128. "FlagDependencyExportsPlugin",
  129. module => {
  130. providedExportsCache.set(module, module.buildMeta.providedExports);
  131. }
  132. );
  133. compilation.hooks.finishRebuildingModule.tap(
  134. "FlagDependencyExportsPlugin",
  135. module => {
  136. module.buildMeta.providedExports = providedExportsCache.get(module);
  137. }
  138. );
  139. }
  140. );
  141. }
  142. }
  143. module.exports = FlagDependencyExportsPlugin;