plugin.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. "use strict";
  2. var __assign = (this && this.__assign) || function () {
  3. __assign = Object.assign || function(t) {
  4. for (var s, i = 1, n = arguments.length; i < n; i++) {
  5. s = arguments[i];
  6. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  7. t[p] = s[p];
  8. }
  9. return t;
  10. };
  11. return __assign.apply(this, arguments);
  12. };
  13. Object.defineProperty(exports, "__esModule", { value: true });
  14. exports.TsconfigPathsPlugin = void 0;
  15. var chalk = require("chalk");
  16. var TsconfigPaths = require("tsconfig-paths");
  17. var path = require("path");
  18. var Options = require("./options");
  19. var Logger = require("./logger");
  20. // eslint-disable-next-line no-redeclare
  21. var getInnerRequest = require("enhanced-resolve/lib/getInnerRequest");
  22. var TsconfigPathsPlugin = /** @class */ (function () {
  23. function TsconfigPathsPlugin(rawOptions) {
  24. var _this = this;
  25. if (rawOptions === void 0) { rawOptions = {}; }
  26. this.source = "described-resolve";
  27. this.target = "resolve";
  28. var options = Options.getOptions(rawOptions);
  29. this.extensions = options.extensions;
  30. this.referenceMatchMap = {};
  31. // const colors = new chalk.constructor({ enabled: options.colors });
  32. this.log = Logger.makeLogger(options, new chalk.Instance({ level: options.colors ? undefined : 0 }));
  33. var context = options.context || process.cwd();
  34. var loadFrom = options.configFile || context;
  35. var loadResult = loadConfig(loadFrom, this.log);
  36. if (loadResult.resultType === "success") {
  37. this.baseUrl = options.baseUrl || loadResult.baseUrl;
  38. this.absoluteBaseUrl = options.baseUrl
  39. ? path.resolve(options.baseUrl)
  40. : loadResult.absoluteBaseUrl;
  41. this.matchPath = TsconfigPaths.createMatchPathAsync(this.absoluteBaseUrl, loadResult.paths, options.mainFields);
  42. if (options.references) {
  43. options.references.reduce(function (pathMap, reference) {
  44. if (reference) {
  45. var referenceResult = loadConfig(reference, _this.log);
  46. if (referenceResult.resultType === "success") {
  47. var paths = referenceResult.paths, absoluteBaseUrl = referenceResult.absoluteBaseUrl;
  48. pathMap[absoluteBaseUrl] = TsconfigPaths.createMatchPathAsync(absoluteBaseUrl, paths, options.mainFields);
  49. }
  50. }
  51. return pathMap;
  52. }, this.referenceMatchMap);
  53. }
  54. }
  55. }
  56. TsconfigPathsPlugin.prototype.apply = function (resolver) {
  57. if (!resolver) {
  58. this.log.logWarning("tsconfig-paths-webpack-plugin: Found no resolver, not applying tsconfig-paths-webpack-plugin");
  59. return;
  60. }
  61. // The file system only exists when the plugin is in the resolve context. This means it's also properly placed in the resolve.plugins array.
  62. // If not, we should warn the user that this plugin should be placed in resolve.plugins and not the plugins array of the root config for example.
  63. // This should hopefully prevent issues like: https://github.com/dividab/tsconfig-paths-webpack-plugin/issues/9
  64. if (!("fileSystem" in resolver)) {
  65. this.log.logWarning("tsconfig-paths-webpack-plugin: No file system found on resolver." +
  66. " Please make sure you've placed the plugin in the correct part of the configuration." +
  67. " This plugin is a resolver plugin and should be placed in the resolve part of the Webpack configuration.");
  68. return;
  69. }
  70. // getHook will only exist in Webpack 4 & 5, if so we should comply to the Webpack 4 plugin system.
  71. if ("getHook" in resolver && typeof resolver.getHook === "function") {
  72. resolver
  73. .getHook(this.source)
  74. .tapAsync({ name: "TsconfigPathsPlugin" }, createPluginCallback(this.referenceMatchMap, this.matchPath, resolver, this.absoluteBaseUrl, resolver.getHook(this.target), this.extensions));
  75. }
  76. else if ("plugin" in resolver) {
  77. // This is the legacy (Webpack < 4.0.0) way of using the plugin system.
  78. var legacyResolver = resolver;
  79. legacyResolver.plugin(this.source, createPluginLegacy(this.matchPath, resolver, this.absoluteBaseUrl, this.target, this.extensions));
  80. }
  81. };
  82. return TsconfigPathsPlugin;
  83. }());
  84. exports.TsconfigPathsPlugin = TsconfigPathsPlugin;
  85. function loadConfig(configPath, logger) {
  86. var loadResult = TsconfigPaths.loadConfig(configPath);
  87. if (loadResult.resultType === "failed") {
  88. logger.logError("Failed to load " + configPath + ": " + loadResult.message);
  89. }
  90. else {
  91. logger.logInfo("tsconfig-paths-webpack-plugin: Using config file at " + loadResult.configFileAbsolutePath);
  92. }
  93. return loadResult;
  94. }
  95. function createPluginCallback(referenceMatchMap, baseMatchPath, resolver, baseAbsoluteBaseUrl, hook, extensions) {
  96. var fileExistAsync = createFileExistAsync(resolver.fileSystem);
  97. var readJsonAsync = createReadJsonAsync(resolver.fileSystem);
  98. return function (request, resolveContext, callback) {
  99. var _a, _b;
  100. var innerRequest = getInnerRequest(resolver, request);
  101. if (!innerRequest ||
  102. ((_a = request === null || request === void 0 ? void 0 : request.request) === null || _a === void 0 ? void 0 : _a.startsWith(".")) ||
  103. ((_b = request === null || request === void 0 ? void 0 : request.request) === null || _b === void 0 ? void 0 : _b.startsWith(".."))) {
  104. return callback();
  105. }
  106. // Find the base URL and matchPath instance
  107. // Quickly check if the request path is a known baseUrl
  108. // Then check if the path is a child of a reference baseUrl
  109. var absoluteBaseUrl = baseAbsoluteBaseUrl;
  110. if (typeof request.path === "string" &&
  111. request.path !== baseAbsoluteBaseUrl) {
  112. if (referenceMatchMap[request.path]) {
  113. absoluteBaseUrl = request.path;
  114. }
  115. else {
  116. var referenceUrl = Object.keys(referenceMatchMap).find(function (refBaseUrl) {
  117. var relative = path.relative(refBaseUrl, request.path || "");
  118. return (relative &&
  119. !relative.startsWith("..") &&
  120. !path.isAbsolute(relative));
  121. });
  122. if (referenceUrl) {
  123. absoluteBaseUrl = referenceUrl;
  124. }
  125. }
  126. }
  127. var matchPath = referenceMatchMap[absoluteBaseUrl] || baseMatchPath;
  128. matchPath(innerRequest, readJsonAsync, fileExistAsync, extensions, function (err, foundMatch) {
  129. if (err) {
  130. return callback(err);
  131. }
  132. if (!foundMatch) {
  133. return callback();
  134. }
  135. var newRequest = __assign(__assign({}, request), { request: foundMatch, path: absoluteBaseUrl });
  136. // Only at this point we are sure we are dealing with the latest Webpack version (>= 4.0.0)
  137. // So only now can we require the createInnerContext function.
  138. // (It doesn't exist in legacy versions)
  139. var createInnerContext = require("enhanced-resolve/lib/createInnerContext");
  140. return resolver.doResolve(hook, newRequest, "Resolved request '" + innerRequest + "' to '" + foundMatch + "' using tsconfig.json paths mapping",
  141. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  142. createInnerContext(__assign({}, resolveContext)), function (err2, result2) {
  143. // Pattern taken from:
  144. // https://github.com/webpack/enhanced-resolve/blob/42ff594140582c3f8f86811f95dea7bf6774a1c8/lib/AliasPlugin.js#L44
  145. if (err2) {
  146. return callback(err2);
  147. }
  148. // Don't allow other aliasing or raw request
  149. if (result2 === undefined) {
  150. return callback(undefined, undefined);
  151. }
  152. callback(undefined, result2);
  153. });
  154. });
  155. };
  156. }
  157. function createPluginLegacy(matchPath, resolver, absoluteBaseUrl, target, extensions) {
  158. var fileExistAsync = createFileExistAsync(resolver.fileSystem);
  159. var readJsonAsync = createReadJsonAsync(resolver.fileSystem);
  160. return function (request, callback) {
  161. var innerRequest = getInnerRequest(resolver, request);
  162. if (!innerRequest ||
  163. innerRequest.startsWith(".") ||
  164. innerRequest.startsWith("..")) {
  165. return callback();
  166. }
  167. matchPath(innerRequest, readJsonAsync, fileExistAsync, extensions, function (err, foundMatch) {
  168. if (err) {
  169. return callback(err);
  170. }
  171. if (!foundMatch) {
  172. return callback();
  173. }
  174. var newRequest = __assign(__assign({}, request), { request: foundMatch, path: absoluteBaseUrl });
  175. // Only at this point we are sure we are dealing with a legacy Webpack version (< 4.0.0)
  176. // So only now can we require the createInnerCallback function.
  177. // (It's already deprecated and might be removed down the line).
  178. var createInnerCallback = require("enhanced-resolve/lib/createInnerCallback");
  179. return resolver.doResolve(target, newRequest, "Resolved request '" + innerRequest + "' to '" + foundMatch + "' using tsconfig.json paths mapping", createInnerCallback(function (err2, result2) {
  180. // Note:
  181. // *NOT* using an arrow function here because arguments.length implies we have "this"
  182. // That means "this" has to be in the current function scope, and not the scope above.
  183. // Pattern taken from:
  184. // https://github.com/s-panferov/awesome-typescript-loader/blob/10653beff85f555f1f3b5d4bfd7d21513d0e54a4/src/paths-plugin.ts#L169
  185. if (arguments.length > 0) {
  186. return callback(err2, result2);
  187. }
  188. // don't allow other aliasing or raw request
  189. callback(undefined, undefined);
  190. }, callback));
  191. });
  192. };
  193. }
  194. function readJson(fileSystem, path2, callback) {
  195. if ("readJson" in fileSystem && fileSystem.readJson) {
  196. return fileSystem.readJson(path2, callback);
  197. }
  198. fileSystem.readFile(path2, function (err, buf) {
  199. if (err) {
  200. return callback(err);
  201. }
  202. var data;
  203. try {
  204. // @ts-ignore This will crash if buf is undefined, which I guess it can be...
  205. data = JSON.parse(buf.toString("utf-8"));
  206. }
  207. catch (e) {
  208. return callback(e);
  209. }
  210. return callback(undefined, data);
  211. });
  212. }
  213. function createReadJsonAsync(filesystem) {
  214. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  215. return function (path2, callback2) {
  216. readJson(filesystem, path2, function (err, json) {
  217. // If error assume file does not exist
  218. if (err || !json) {
  219. callback2();
  220. return;
  221. }
  222. callback2(undefined, json);
  223. });
  224. };
  225. }
  226. function createFileExistAsync(filesystem) {
  227. return function (path2, callback2) {
  228. filesystem.stat(path2, function (err, stats) {
  229. // If error assume file does not exist
  230. if (err) {
  231. callback2(undefined, false);
  232. return;
  233. }
  234. callback2(undefined, stats ? stats.isFile() : false);
  235. });
  236. };
  237. }
  238. //# sourceMappingURL=plugin.js.map