ContextReplacementPlugin.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const ContextElementDependency = require("./dependencies/ContextElementDependency");
  7. const { join } = require("./util/fs");
  8. /** @typedef {import("./Compiler")} Compiler */
  9. /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
  10. class ContextReplacementPlugin {
  11. /**
  12. * @param {RegExp} resourceRegExp A regular expression that determines which files will be selected
  13. * @param {TODO=} newContentResource A new resource to replace the match
  14. * @param {TODO=} newContentRecursive If true, all subdirectories are searched for matches
  15. * @param {TODO=} newContentRegExp A regular expression that determines which files will be selected
  16. */
  17. constructor(
  18. resourceRegExp,
  19. newContentResource,
  20. newContentRecursive,
  21. newContentRegExp
  22. ) {
  23. this.resourceRegExp = resourceRegExp;
  24. if (typeof newContentResource === "function") {
  25. this.newContentCallback = newContentResource;
  26. } else if (
  27. typeof newContentResource === "string" &&
  28. typeof newContentRecursive === "object"
  29. ) {
  30. this.newContentResource = newContentResource;
  31. this.newContentCreateContextMap = (fs, callback) => {
  32. callback(null, newContentRecursive);
  33. };
  34. } else if (
  35. typeof newContentResource === "string" &&
  36. typeof newContentRecursive === "function"
  37. ) {
  38. this.newContentResource = newContentResource;
  39. this.newContentCreateContextMap = newContentRecursive;
  40. } else {
  41. if (typeof newContentResource !== "string") {
  42. newContentRegExp = newContentRecursive;
  43. newContentRecursive = newContentResource;
  44. newContentResource = undefined;
  45. }
  46. if (typeof newContentRecursive !== "boolean") {
  47. newContentRegExp = newContentRecursive;
  48. newContentRecursive = undefined;
  49. }
  50. this.newContentResource = newContentResource;
  51. this.newContentRecursive = newContentRecursive;
  52. this.newContentRegExp = newContentRegExp;
  53. }
  54. }
  55. /**
  56. * Apply the plugin
  57. * @param {Compiler} compiler the compiler instance
  58. * @returns {void}
  59. */
  60. apply(compiler) {
  61. const resourceRegExp = this.resourceRegExp;
  62. const newContentCallback = this.newContentCallback;
  63. const newContentResource = this.newContentResource;
  64. const newContentRecursive = this.newContentRecursive;
  65. const newContentRegExp = this.newContentRegExp;
  66. const newContentCreateContextMap = this.newContentCreateContextMap;
  67. compiler.hooks.contextModuleFactory.tap("ContextReplacementPlugin", cmf => {
  68. cmf.hooks.beforeResolve.tap("ContextReplacementPlugin", result => {
  69. if (!result) return;
  70. if (resourceRegExp.test(result.request)) {
  71. if (newContentResource !== undefined) {
  72. result.request = newContentResource;
  73. }
  74. if (newContentRecursive !== undefined) {
  75. result.recursive = newContentRecursive;
  76. }
  77. if (newContentRegExp !== undefined) {
  78. result.regExp = newContentRegExp;
  79. }
  80. if (typeof newContentCallback === "function") {
  81. newContentCallback(result);
  82. } else {
  83. for (const d of result.dependencies) {
  84. if (d.critical) d.critical = false;
  85. }
  86. }
  87. }
  88. return result;
  89. });
  90. cmf.hooks.afterResolve.tap("ContextReplacementPlugin", result => {
  91. if (!result) return;
  92. if (resourceRegExp.test(result.resource)) {
  93. if (newContentResource !== undefined) {
  94. if (
  95. newContentResource.startsWith("/") ||
  96. (newContentResource.length > 1 && newContentResource[1] === ":")
  97. ) {
  98. result.resource = newContentResource;
  99. } else {
  100. result.resource = join(
  101. /** @type {InputFileSystem} */ (compiler.inputFileSystem),
  102. result.resource,
  103. newContentResource
  104. );
  105. }
  106. }
  107. if (newContentRecursive !== undefined) {
  108. result.recursive = newContentRecursive;
  109. }
  110. if (newContentRegExp !== undefined) {
  111. result.regExp = newContentRegExp;
  112. }
  113. if (typeof newContentCreateContextMap === "function") {
  114. result.resolveDependencies =
  115. createResolveDependenciesFromContextMap(
  116. newContentCreateContextMap
  117. );
  118. }
  119. if (typeof newContentCallback === "function") {
  120. const origResource = result.resource;
  121. newContentCallback(result);
  122. if (
  123. result.resource !== origResource &&
  124. !result.resource.startsWith("/") &&
  125. (result.resource.length <= 1 || result.resource[1] !== ":")
  126. ) {
  127. // When the function changed it to an relative path
  128. result.resource = join(
  129. /** @type {InputFileSystem} */ (compiler.inputFileSystem),
  130. origResource,
  131. result.resource
  132. );
  133. }
  134. } else {
  135. for (const d of result.dependencies) {
  136. if (d.critical) d.critical = false;
  137. }
  138. }
  139. }
  140. return result;
  141. });
  142. });
  143. }
  144. }
  145. const createResolveDependenciesFromContextMap = createContextMap => {
  146. const resolveDependenciesFromContextMap = (fs, options, callback) => {
  147. createContextMap(fs, (err, map) => {
  148. if (err) return callback(err);
  149. const dependencies = Object.keys(map).map(key => {
  150. return new ContextElementDependency(
  151. map[key] + options.resourceQuery + options.resourceFragment,
  152. key,
  153. options.category,
  154. options.referencedExports
  155. );
  156. });
  157. callback(null, dependencies);
  158. });
  159. };
  160. return resolveDependenciesFromContextMap;
  161. };
  162. module.exports = ContextReplacementPlugin;