Skip to content

Commit 7bdfcbd

Browse files
clydinhansl
authored andcommitted
refactor(@ngtools/webpack): simplify paths plugin logic
1 parent 99d0a31 commit 7bdfcbd

File tree

2 files changed

+55
-87
lines changed

2 files changed

+55
-87
lines changed

packages/@ngtools/webpack/src/angular_compiler_plugin.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const treeKill = require('tree-kill');
1010
import { WebpackResourceLoader } from './resource_loader';
1111
import { WebpackCompilerHost } from './compiler_host';
1212
import { Tapable } from './webpack';
13-
import { PathsPlugin } from './paths-plugin';
13+
import { resolveWithPaths } from './paths-plugin';
1414
import { findLazyRoutes, LazyRouteMap } from './lazy_routes';
1515
import {
1616
VirtualFileSystemDecorator,
@@ -259,9 +259,6 @@ export class AngularCompilerPlugin implements Tapable {
259259
}
260260
}
261261

262-
// Use an identity function as all our paths are absolute already.
263-
this._moduleResolutionCache = ts.createModuleResolutionCache(this._basePath, x => x);
264-
265262
// Resolve mainPath if provided.
266263
if (options.mainPath) {
267264
this._mainPath = this._compilerHost.resolve(options.mainPath);
@@ -315,6 +312,9 @@ export class AngularCompilerPlugin implements Tapable {
315312
this._updateForkedTypeChecker(this._rootNames, this._getChangedCompilationFiles());
316313
}
317314

315+
// Use an identity function as all our paths are absolute already.
316+
this._moduleResolutionCache = ts.createModuleResolutionCache(this._basePath, x => x);
317+
318318
if (this._JitMode) {
319319
// Create the TypeScript program.
320320
time('AngularCompilerPlugin._createOrUpdateProgram.ts.createProgram');
@@ -617,12 +617,15 @@ export class AngularCompilerPlugin implements Tapable {
617617
});
618618

619619
compiler.plugin('normal-module-factory', (nmf: any) => {
620-
compiler.resolvers.normal.apply(new PathsPlugin({
621-
nmf,
622-
tsConfigPath: this._tsConfigPath,
623-
compilerOptions: this._compilerOptions,
624-
compilerHost: this._compilerHost
625-
}));
620+
nmf.plugin('before-resolve', (request: any, callback: any) => {
621+
resolveWithPaths(
622+
request,
623+
callback,
624+
this._compilerOptions,
625+
this._compilerHost,
626+
this._moduleResolutionCache,
627+
);
628+
});
626629
});
627630
}
628631

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

Lines changed: 42 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,47 @@ import {
1313
const ModulesInRootPlugin: new (a: string, b: string, c: string) => ResolverPlugin
1414
= require('enhanced-resolve/lib/ModulesInRootPlugin');
1515

16-
export interface Mapping {
17-
onlyModule: boolean;
18-
alias: string;
19-
aliasPattern: RegExp;
20-
target: string;
21-
}
16+
export function resolveWithPaths(
17+
request: NormalModuleFactoryRequest,
18+
callback: Callback<NormalModuleFactoryRequest>,
19+
compilerOptions: ts.CompilerOptions,
20+
host: ts.CompilerHost,
21+
cache?: ts.ModuleResolutionCache,
22+
) {
23+
if (!request) {
24+
callback(null, request);
25+
return;
26+
}
27+
28+
// Only work on Javascript/TypeScript issuers.
29+
if (!request.contextInfo.issuer || !request.contextInfo.issuer.match(/\.[jt]s$/)) {
30+
callback(null, request);
31+
return;
32+
}
2233

34+
const moduleResolver = ts.resolveModuleName(
35+
request.request,
36+
request.contextInfo.issuer,
37+
compilerOptions,
38+
host,
39+
cache
40+
);
41+
42+
let moduleFilePath = moduleResolver.resolvedModule
43+
&& moduleResolver.resolvedModule.resolvedFileName;
44+
45+
// If TypeScript gives us a .d.ts it's probably a node module and we need to let webpack
46+
// do the resolution.
47+
if (moduleFilePath) {
48+
moduleFilePath = moduleFilePath.replace(/\.d\.ts$/, '.js');
49+
if (host.fileExists(moduleFilePath)) {
50+
request.request = moduleFilePath;
51+
}
52+
}
2353

24-
function escapeRegExp(str: string): string {
25-
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
54+
callback(null, request);
2655
}
2756

28-
2957
export interface PathsPluginOptions {
3058
nmf: NormalModuleFactory;
3159
tsConfigPath: string;
@@ -35,15 +63,11 @@ export interface PathsPluginOptions {
3563

3664
export class PathsPlugin implements Tapable {
3765
private _nmf: NormalModuleFactory;
38-
private _tsConfigPath: string;
3966
private _compilerOptions: ts.CompilerOptions;
4067
private _host: ts.CompilerHost;
4168

4269
source: string;
4370
target: string;
44-
45-
private _mappings: Mapping[];
46-
4771
private _absoluteBaseUrl: string;
4872

4973
private static _loadOptionsFromTsConfig(tsConfigPath: string, host?: ts.CompilerHost):
@@ -66,12 +90,12 @@ export class PathsPlugin implements Tapable {
6690
// This could happen in JavaScript.
6791
throw new Error('tsConfigPath option is mandatory.');
6892
}
69-
this._tsConfigPath = options.tsConfigPath;
93+
const tsConfigPath = options.tsConfigPath;
7094

7195
if (options.compilerOptions) {
7296
this._compilerOptions = options.compilerOptions;
7397
} else {
74-
this._compilerOptions = PathsPlugin._loadOptionsFromTsConfig(this._tsConfigPath);
98+
this._compilerOptions = PathsPlugin._loadOptionsFromTsConfig(tsConfigPath);
7599
}
76100

77101
if (options.compilerHost) {
@@ -85,33 +109,9 @@ export class PathsPlugin implements Tapable {
85109
this.target = 'resolve';
86110

87111
this._absoluteBaseUrl = path.resolve(
88-
path.dirname(this._tsConfigPath),
112+
path.dirname(tsConfigPath),
89113
this._compilerOptions.baseUrl || '.'
90114
);
91-
92-
this._mappings = [];
93-
let paths = this._compilerOptions.paths || {};
94-
Object.keys(paths).forEach(alias => {
95-
let onlyModule = alias.indexOf('*') === -1;
96-
let excapedAlias = escapeRegExp(alias);
97-
let targets = paths[alias];
98-
targets.forEach(target => {
99-
let aliasPattern: RegExp;
100-
if (onlyModule) {
101-
aliasPattern = new RegExp(`^${excapedAlias}$`);
102-
} else {
103-
let withStarCapturing = excapedAlias.replace('\\*', '(.*)');
104-
aliasPattern = new RegExp(`^${withStarCapturing}`);
105-
}
106-
107-
this._mappings.push({
108-
onlyModule,
109-
alias,
110-
aliasPattern,
111-
target: target
112-
});
113-
});
114-
});
115115
}
116116

117117
apply(resolver: ResolverPlugin): void {
@@ -121,43 +121,8 @@ export class PathsPlugin implements Tapable {
121121
resolver.apply(new ModulesInRootPlugin('module', this._absoluteBaseUrl, 'resolve'));
122122
}
123123

124-
this._nmf.plugin('before-resolve', (request: NormalModuleFactoryRequest,
125-
callback: Callback<any>) => {
126-
// Only work on TypeScript issuers.
127-
if (!request.contextInfo.issuer || !request.contextInfo.issuer.match(/\.[jt]s$/)) {
128-
return callback(null, request);
129-
}
130-
131-
for (let mapping of this._mappings) {
132-
const match = request.request.match(mapping.aliasPattern);
133-
if (!match) { continue; }
134-
let newRequestStr = mapping.target;
135-
if (!mapping.onlyModule) {
136-
newRequestStr = newRequestStr.replace('*', match[1]);
137-
}
138-
const moduleResolver = ts.resolveModuleName(
139-
request.request,
140-
request.contextInfo.issuer,
141-
this._compilerOptions,
142-
this._host
143-
);
144-
let moduleFilePath = moduleResolver.resolvedModule
145-
&& moduleResolver.resolvedModule.resolvedFileName;
146-
147-
// If TypeScript gives us a .d.ts it's probably a node module and we need to let webpack
148-
// do the resolution.
149-
if (moduleFilePath && moduleFilePath.endsWith('.d.ts')) {
150-
moduleFilePath = moduleFilePath.replace(/\.d\.ts$/, '.js');
151-
if (!this._host.fileExists(moduleFilePath)) {
152-
continue;
153-
}
154-
}
155-
if (moduleFilePath) {
156-
return callback(null, Object.assign({}, request, { request: moduleFilePath }));
157-
}
158-
}
159-
160-
return callback(null, request);
124+
this._nmf.plugin('before-resolve', (request, callback) => {
125+
resolveWithPaths(request, callback, this._compilerOptions, this._host);
161126
});
162127
}
163128
}

0 commit comments

Comments
 (0)