AliasPlugin.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const forEachBail = require("./forEachBail");
  7. const { PathType, getType } = require("./util/path");
  8. /** @typedef {import("./Resolver")} Resolver */
  9. /** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */
  10. /** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */
  11. /** @typedef {{alias: string|Array<string>|false, name: string, onlyModule?: boolean}} AliasOption */
  12. module.exports = class AliasPlugin {
  13. /**
  14. * @param {string | ResolveStepHook} source source
  15. * @param {AliasOption | Array<AliasOption>} options options
  16. * @param {string | ResolveStepHook} target target
  17. */
  18. constructor(source, options, target) {
  19. this.source = source;
  20. this.options = Array.isArray(options) ? options : [options];
  21. this.target = target;
  22. }
  23. /**
  24. * @param {Resolver} resolver the resolver
  25. * @returns {void}
  26. */
  27. apply(resolver) {
  28. const target = resolver.ensureHook(this.target);
  29. const getAbsolutePathWithSlashEnding = maybeAbsolutePath => {
  30. const type = getType(maybeAbsolutePath);
  31. if (type === PathType.AbsolutePosix || type === PathType.AbsoluteWin) {
  32. return resolver.join(maybeAbsolutePath, "_").slice(0, -1);
  33. }
  34. return null;
  35. };
  36. const isSubPath = (path, maybeSubPath) => {
  37. const absolutePath = getAbsolutePathWithSlashEnding(maybeSubPath);
  38. if (!absolutePath) return false;
  39. return path.startsWith(absolutePath);
  40. };
  41. resolver
  42. .getHook(this.source)
  43. .tapAsync("AliasPlugin", (request, resolveContext, callback) => {
  44. const innerRequest = request.request || request.path;
  45. if (!innerRequest) return callback();
  46. forEachBail(
  47. this.options,
  48. (item, callback) => {
  49. let shouldStop = false;
  50. if (
  51. innerRequest === item.name ||
  52. (!item.onlyModule &&
  53. (request.request
  54. ? innerRequest.startsWith(`${item.name}/`)
  55. : isSubPath(innerRequest, item.name)))
  56. ) {
  57. const remainingRequest = innerRequest.substr(item.name.length);
  58. const resolveWithAlias = (alias, callback) => {
  59. if (alias === false) {
  60. /** @type {ResolveRequest} */
  61. const ignoreObj = {
  62. ...request,
  63. path: false
  64. };
  65. if (typeof resolveContext.yield === "function") {
  66. resolveContext.yield(ignoreObj);
  67. return callback(null, null);
  68. }
  69. return callback(null, ignoreObj);
  70. }
  71. if (
  72. innerRequest !== alias &&
  73. !innerRequest.startsWith(alias + "/")
  74. ) {
  75. shouldStop = true;
  76. const newRequestStr = alias + remainingRequest;
  77. const obj = {
  78. ...request,
  79. request: newRequestStr,
  80. fullySpecified: false
  81. };
  82. return resolver.doResolve(
  83. target,
  84. obj,
  85. "aliased with mapping '" +
  86. item.name +
  87. "': '" +
  88. alias +
  89. "' to '" +
  90. newRequestStr +
  91. "'",
  92. resolveContext,
  93. (err, result) => {
  94. if (err) return callback(err);
  95. if (result) return callback(null, result);
  96. return callback();
  97. }
  98. );
  99. }
  100. return callback();
  101. };
  102. const stoppingCallback = (err, result) => {
  103. if (err) return callback(err);
  104. if (result) return callback(null, result);
  105. // Don't allow other aliasing or raw request
  106. if (shouldStop) return callback(null, null);
  107. return callback();
  108. };
  109. if (Array.isArray(item.alias)) {
  110. return forEachBail(
  111. item.alias,
  112. resolveWithAlias,
  113. stoppingCallback
  114. );
  115. } else {
  116. return resolveWithAlias(item.alias, stoppingCallback);
  117. }
  118. }
  119. return callback();
  120. },
  121. callback
  122. );
  123. });
  124. }
  125. };