RequireContextPlugin.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { cachedSetProperty } = require("../util/cleverMerge");
  7. const ContextElementDependency = require("./ContextElementDependency");
  8. const RequireContextDependency = require("./RequireContextDependency");
  9. const RequireContextDependencyParserPlugin = require("./RequireContextDependencyParserPlugin");
  10. /** @typedef {import("../../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
  11. /** @typedef {import("../Compiler")} Compiler */
  12. /** @type {ResolveOptions} */
  13. const EMPTY_RESOLVE_OPTIONS = {};
  14. class RequireContextPlugin {
  15. /**
  16. * Apply the plugin
  17. * @param {Compiler} compiler the compiler instance
  18. * @returns {void}
  19. */
  20. apply(compiler) {
  21. compiler.hooks.compilation.tap(
  22. "RequireContextPlugin",
  23. (compilation, { contextModuleFactory, normalModuleFactory }) => {
  24. compilation.dependencyFactories.set(
  25. RequireContextDependency,
  26. contextModuleFactory
  27. );
  28. compilation.dependencyTemplates.set(
  29. RequireContextDependency,
  30. new RequireContextDependency.Template()
  31. );
  32. compilation.dependencyFactories.set(
  33. ContextElementDependency,
  34. normalModuleFactory
  35. );
  36. const handler = (parser, parserOptions) => {
  37. if (
  38. parserOptions.requireContext !== undefined &&
  39. !parserOptions.requireContext
  40. )
  41. return;
  42. new RequireContextDependencyParserPlugin().apply(parser);
  43. };
  44. normalModuleFactory.hooks.parser
  45. .for("javascript/auto")
  46. .tap("RequireContextPlugin", handler);
  47. normalModuleFactory.hooks.parser
  48. .for("javascript/dynamic")
  49. .tap("RequireContextPlugin", handler);
  50. contextModuleFactory.hooks.alternativeRequests.tap(
  51. "RequireContextPlugin",
  52. (items, options) => {
  53. if (items.length === 0) return items;
  54. const finalResolveOptions = compiler.resolverFactory.get(
  55. "normal",
  56. cachedSetProperty(
  57. options.resolveOptions || EMPTY_RESOLVE_OPTIONS,
  58. "dependencyType",
  59. options.category
  60. )
  61. ).options;
  62. let newItems;
  63. if (!finalResolveOptions.fullySpecified) {
  64. newItems = [];
  65. for (const item of items) {
  66. const { request, context } = item;
  67. for (const ext of finalResolveOptions.extensions) {
  68. if (request.endsWith(ext)) {
  69. newItems.push({
  70. context,
  71. request: request.slice(0, -ext.length)
  72. });
  73. }
  74. }
  75. if (!finalResolveOptions.enforceExtension) {
  76. newItems.push(item);
  77. }
  78. }
  79. items = newItems;
  80. newItems = [];
  81. for (const obj of items) {
  82. const { request, context } = obj;
  83. for (const mainFile of finalResolveOptions.mainFiles) {
  84. if (request.endsWith(`/${mainFile}`)) {
  85. newItems.push({
  86. context,
  87. request: request.slice(0, -mainFile.length)
  88. });
  89. newItems.push({
  90. context,
  91. request: request.slice(0, -mainFile.length - 1)
  92. });
  93. }
  94. }
  95. newItems.push(obj);
  96. }
  97. items = newItems;
  98. }
  99. newItems = [];
  100. for (const item of items) {
  101. let hideOriginal = false;
  102. for (const modulesItems of finalResolveOptions.modules) {
  103. if (Array.isArray(modulesItems)) {
  104. for (const dir of modulesItems) {
  105. if (item.request.startsWith(`./${dir}/`)) {
  106. newItems.push({
  107. context: item.context,
  108. request: item.request.slice(dir.length + 3)
  109. });
  110. hideOriginal = true;
  111. }
  112. }
  113. } else {
  114. const dir = modulesItems.replace(/\\/g, "/");
  115. const fullPath =
  116. item.context.replace(/\\/g, "/") + item.request.slice(1);
  117. if (fullPath.startsWith(dir)) {
  118. newItems.push({
  119. context: item.context,
  120. request: fullPath.slice(dir.length + 1)
  121. });
  122. }
  123. }
  124. }
  125. if (!hideOriginal) {
  126. newItems.push(item);
  127. }
  128. }
  129. return newItems;
  130. }
  131. );
  132. }
  133. );
  134. }
  135. }
  136. module.exports = RequireContextPlugin;