Skip to content

Commit 2e4ee28

Browse files
clydinalan-agius4
authored andcommitted
refactor(@ngtools/webpack): support both sync and async resolvers with TypeScript paths plugin
Usage of async functions and promises were removed from the TypeScript paths resolver plugin to allow it to be used with both a synchronous and asychronous Webpack resolver.
1 parent a30525b commit 2e4ee28

File tree

1 file changed

+76
-67
lines changed

1 file changed

+76
-67
lines changed

packages/ngtools/webpack/src/paths-plugin.ts

Lines changed: 76 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@ import { CompilerOptions, MapLike } from 'typescript';
1111

1212
const getInnerRequest = require('enhanced-resolve/lib/getInnerRequest');
1313

14-
interface NormalModuleFactoryRequest {
15-
request: string;
16-
context: { issuer: string };
17-
contextInfo: { issuer: string };
18-
typescriptPathMapped?: boolean;
19-
}
20-
2114
// eslint-disable-next-line @typescript-eslint/no-empty-interface
2215
export interface TypeScriptPathsPluginOptions extends Pick<CompilerOptions, 'paths' | 'baseUrl'> {}
2316

@@ -29,78 +22,94 @@ export class TypeScriptPathsPlugin {
2922
}
3023

3124
// eslint-disable-next-line @typescript-eslint/no-explicit-any
32-
apply(resolver: any) {
25+
apply(resolver: import('enhanced-resolve').Resolver) {
3326
const target = resolver.ensureHook('resolve');
34-
const resolveAsync = (request: NormalModuleFactoryRequest, requestContext: {}) => {
35-
return new Promise<NormalModuleFactoryRequest | undefined>((resolve, reject) => {
36-
resolver.doResolve(
37-
target,
38-
request,
39-
'',
40-
requestContext,
41-
(error: Error | null, result: NormalModuleFactoryRequest | undefined) => {
42-
if (error) {
43-
reject(error);
44-
} else {
45-
resolve(result);
46-
}
47-
},
48-
);
49-
});
50-
};
51-
52-
resolver
53-
.getHook('described-resolve')
54-
.tapPromise(
55-
'TypeScriptPathsPlugin',
56-
async (request: NormalModuleFactoryRequest, resolveContext: {}) => {
57-
if (!this.options) {
58-
throw new Error('TypeScriptPathsPlugin options were not provided.');
59-
}
6027

61-
if (!request || request.typescriptPathMapped) {
62-
return;
63-
}
28+
resolver.getHook('described-resolve').tapAsync(
29+
'TypeScriptPathsPlugin',
30+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
31+
(request: any, resolveContext, callback) => {
32+
if (!this.options) {
33+
callback();
6434

65-
const originalRequest = getInnerRequest(resolver, request);
66-
if (!originalRequest) {
67-
return;
68-
}
35+
return;
36+
}
6937

70-
// Only work on Javascript/TypeScript issuers.
71-
if (!request.context.issuer || !request.context.issuer.match(/\.[jt]sx?$/)) {
72-
return;
73-
}
38+
if (!request || request.typescriptPathMapped) {
39+
callback();
7440

75-
// Relative or absolute requests are not mapped
76-
if (originalRequest.startsWith('.') || originalRequest.startsWith('/')) {
77-
return;
78-
}
41+
return;
42+
}
43+
44+
const originalRequest = getInnerRequest(resolver, request);
45+
if (!originalRequest) {
46+
callback();
47+
48+
return;
49+
}
50+
51+
// Only work on Javascript/TypeScript issuers.
52+
if (!request.context.issuer || !request.context.issuer.match(/\.[jt]sx?$/)) {
53+
callback();
54+
55+
return;
56+
}
57+
58+
// Relative or absolute requests are not mapped
59+
if (originalRequest.startsWith('.') || originalRequest.startsWith('/')) {
60+
callback();
61+
62+
return;
63+
}
64+
65+
// Ignore all webpack special requests
66+
if (originalRequest.startsWith('!!')) {
67+
callback();
68+
69+
return;
70+
}
71+
72+
const replacements = findReplacements(originalRequest, this.options.paths || {});
73+
74+
const tryResolve = () => {
75+
const potential = replacements.shift();
76+
if (!potential) {
77+
callback();
7978

80-
// Ignore all webpack special requests
81-
if (originalRequest.startsWith('!!')) {
8279
return;
8380
}
8481

85-
const replacements = findReplacements(originalRequest, this.options.paths || {});
86-
for (const potential of replacements) {
87-
const potentialRequest = {
88-
...request,
89-
request: path.resolve(this.options.baseUrl || '', potential),
90-
typescriptPathMapped: true,
91-
};
92-
const result = await resolveAsync(potentialRequest, resolveContext);
93-
94-
if (result) {
95-
return result;
96-
}
97-
}
98-
},
99-
);
82+
const potentialRequest = {
83+
...request,
84+
request: path.resolve(this.options?.baseUrl || '', potential),
85+
typescriptPathMapped: true,
86+
};
87+
88+
resolver.doResolve(
89+
target,
90+
potentialRequest,
91+
'',
92+
resolveContext,
93+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
94+
(error: Error | null, result: any) => {
95+
if (error) {
96+
callback(error);
97+
} else if (result) {
98+
callback(undefined, result);
99+
} else {
100+
tryResolve();
101+
}
102+
},
103+
);
104+
};
105+
106+
tryResolve();
107+
},
108+
);
100109
}
101110
}
102111

103-
function findReplacements(originalRequest: string, paths: MapLike<string[]>): Iterable<string> {
112+
function findReplacements(originalRequest: string, paths: MapLike<string[]>): string[] {
104113
// check if any path mapping rules are relevant
105114
const pathMapOptions = [];
106115
for (const pattern in paths) {

0 commit comments

Comments
 (0)