UNPKG

8.09 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const chalk_1 = require("chalk");
4const TsconfigPaths = require("tsconfig-paths");
5const path = require("path");
6const Options = require("./options");
7const Logger = require("./logger");
8const getInnerRequest = require("enhanced-resolve/lib/getInnerRequest");
9class TsconfigPathsPlugin {
10 constructor(rawOptions = {}) {
11 this.source = "described-resolve";
12 this.target = "resolve";
13 const options = Options.getOptions(rawOptions);
14 this.extensions = options.extensions;
15 const colors = new chalk_1.default.constructor({ enabled: options.colors });
16 this.log = Logger.makeLogger(options, colors);
17 const context = options.context || process.cwd();
18 const loadFrom = options.configFile || context;
19 const loadResult = TsconfigPaths.loadConfig(loadFrom);
20 if (loadResult.resultType === "failed") {
21 this.log.logError(`Failed to load tsconfig.json: ${loadResult.message}`);
22 }
23 else {
24 this.log.logInfo(`tsconfig-paths-webpack-plugin: Using config file at ${loadResult.configFileAbsolutePath}`);
25 this.baseUrl = options.baseUrl || loadResult.baseUrl;
26 this.absoluteBaseUrl = options.baseUrl
27 ? path.resolve(options.baseUrl)
28 : loadResult.absoluteBaseUrl;
29 this.matchPath = TsconfigPaths.createMatchPathAsync(this.absoluteBaseUrl, loadResult.paths);
30 }
31 }
32 apply(resolver) {
33 const { baseUrl } = this;
34 if (!baseUrl) {
35 // Nothing to do if there is no baseUrl
36 this.log.logWarning("tsconfig-paths-webpack-plugin: Found no baseUrl in tsconfig.json, not applying tsconfig-paths-webpack-plugin");
37 return;
38 }
39 // 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.
40 // 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.
41 // This should hopefully prevent issues like: https://github.com/dividab/tsconfig-paths-webpack-plugin/issues/9
42 if (!resolver.fileSystem) {
43 this.log.logWarning("tsconfig-paths-webpack-plugin: No file system found on resolver." +
44 " Please make sure you've placed the plugin in the correct part of the configuration." +
45 " This plugin is a resolver plugin and should be placed in the resolve part of the Webpack configuration.");
46 return;
47 }
48 // getHook will only exist in Webpack 4, if so we should comply to the Webpack 4 plugin system.
49 if (resolver.getHook && typeof resolver.getHook === "function") {
50 resolver
51 .getHook(this.source)
52 .tapAsync({ name: "TsconfigPathsPlugin" }, createPluginCallback(this.matchPath, resolver, this.absoluteBaseUrl, resolver.getHook(this.target), this.extensions));
53 }
54 else {
55 // This is the legacy (Webpack < 4.0.0) way of using the plugin system.
56 resolver.plugin(this.source, createPluginLegacy(this.matchPath, resolver, this.absoluteBaseUrl, this.target, this.extensions));
57 }
58 }
59}
60exports.TsconfigPathsPlugin = TsconfigPathsPlugin;
61function createPluginCallback(matchPath, resolver, absoluteBaseUrl, hook, extensions) {
62 const fileExistAsync = createFileExistAsync(resolver.fileSystem);
63 const readJsonAsync = createReadJsonAsync(resolver.fileSystem);
64 return (request, resolveContext, callback) => {
65 const innerRequest = getInnerRequest(resolver, request);
66 if (!innerRequest ||
67 (innerRequest.startsWith(".") || innerRequest.startsWith(".."))) {
68 return callback();
69 }
70 matchPath(innerRequest, readJsonAsync, fileExistAsync, extensions, (err, foundMatch) => {
71 if (err) {
72 return callback(err);
73 }
74 if (!foundMatch) {
75 return callback();
76 }
77 const newRequest = Object.assign({}, request, { request: foundMatch, path: absoluteBaseUrl });
78 // Only at this point we are sure we are dealing with the latest Webpack version (>= 4.0.0)
79 // So only now can we require the createInnerContext function.
80 // (It doesn't exist in legacy versions)
81 const createInnerContext = require("enhanced-resolve/lib/createInnerContext");
82 return resolver.doResolve(hook, newRequest, `Resolved request '${innerRequest}' to '${foundMatch}' using tsconfig.json paths mapping`, createInnerContext(Object.assign({}, resolveContext)), (err2, result2) => {
83 // Pattern taken from:
84 // https://github.com/webpack/enhanced-resolve/blob/42ff594140582c3f8f86811f95dea7bf6774a1c8/lib/AliasPlugin.js#L44
85 if (err2) {
86 return callback(err2);
87 }
88 // Don't allow other aliasing or raw request
89 if (result2 === undefined) {
90 return callback(null, null);
91 }
92 callback(null, result2);
93 });
94 });
95 };
96}
97function createPluginLegacy(matchPath, resolver, absoluteBaseUrl, target, extensions) {
98 const fileExistAsync = createFileExistAsync(resolver.fileSystem);
99 const readJsonAsync = createReadJsonAsync(resolver.fileSystem);
100 return (request, callback) => {
101 const innerRequest = getInnerRequest(resolver, request);
102 if (!innerRequest ||
103 (innerRequest.startsWith(".") || innerRequest.startsWith(".."))) {
104 return callback();
105 }
106 matchPath(innerRequest, readJsonAsync, fileExistAsync, extensions, (err, foundMatch) => {
107 if (err) {
108 return callback(err);
109 }
110 if (!foundMatch) {
111 return callback();
112 }
113 const newRequest = Object.assign({}, request, { request: foundMatch, path: absoluteBaseUrl });
114 // Only at this point we are sure we are dealing with a legacy Webpack version (< 4.0.0)
115 // So only now can we require the createInnerCallback function.
116 // (It's already deprecated and might be removed down the line).
117 const createInnerCallback = require("enhanced-resolve/lib/createInnerCallback");
118 return resolver.doResolve(target, newRequest, `Resolved request '${innerRequest}' to '${foundMatch}' using tsconfig.json paths mapping`, createInnerCallback(function (err2, result2) {
119 // Note:
120 // *NOT* using an arrow function here because arguments.length implies we have "this"
121 // That means "this" has to be in the current function scope, and not the scope above.
122 // Pattern taken from:
123 // https://github.com/s-panferov/awesome-typescript-loader/blob/10653beff85f555f1f3b5d4bfd7d21513d0e54a4/src/paths-plugin.ts#L169
124 if (arguments.length > 0) {
125 return callback(err2, result2);
126 }
127 // don't allow other aliasing or raw request
128 callback(null, null);
129 }, callback));
130 });
131 };
132}
133function createReadJsonAsync(filesystem) {
134 // tslint:disable-next-line:no-any
135 return (path2, callback2) => {
136 filesystem.readJson(path2, (err, json) => {
137 // If error assume file does not exist
138 if (err || !json) {
139 callback2();
140 return;
141 }
142 callback2(undefined, json);
143 });
144 };
145}
146function createFileExistAsync(filesystem) {
147 return (path2, callback2) => {
148 filesystem.stat(path2, (err, stats) => {
149 // If error assume file does not exist
150 if (err) {
151 callback2(undefined, false);
152 return;
153 }
154 callback2(undefined, stats ? stats.isFile() : false);
155 });
156 };
157}