Skip to content

Commit 1484868

Browse files
Chris FitzgeraldBrocco
Chris Fitzgerald
authored andcommitted
fix(@ngtools/webpack): fix paths-plugin to allow '*' as alias
Closes #5033
1 parent e4cedbb commit 1484868

File tree

6 files changed

+57
-90
lines changed

6 files changed

+57
-90
lines changed

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
"diff": "^3.1.0",
5151
"ember-cli-normalize-entity-name": "^1.0.0",
5252
"ember-cli-string-utils": "^1.0.0",
53-
"enhanced-resolve": "^3.1.0",
5453
"exports-loader": "^0.6.3",
5554
"extract-text-webpack-plugin": "^2.1.0",
5655
"file-loader": "^0.10.0",

packages/@ngtools/webpack/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
"npm": ">= 3.0.0"
2626
},
2727
"dependencies": {
28-
"enhanced-resolve": "^3.1.0",
2928
"loader-utils": "^1.0.2",
3029
"magic-string": "^0.19.0",
3130
"source-map": "^0.5.6"
+35-88
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,25 @@
11
import * as path from 'path';
22
import * as ts from 'typescript';
3-
import {Request, ResolverPlugin, Callback, Tapable} from './webpack';
4-
5-
6-
const ModulesInRootPlugin: new (a: string, b: string, c: string) => ResolverPlugin
7-
= require('enhanced-resolve/lib/ModulesInRootPlugin');
8-
9-
interface CreateInnerCallback {
10-
(callback: Callback<any>,
11-
options: Callback<any>,
12-
message?: string,
13-
messageOptional?: string): Callback<any>;
14-
}
15-
16-
const createInnerCallback: CreateInnerCallback
17-
= require('enhanced-resolve/lib/createInnerCallback');
18-
const getInnerRequest: (resolver: ResolverPlugin, request: Request) => string
19-
= require('enhanced-resolve/lib/getInnerRequest');
20-
3+
import {Callback, Tapable, NormalModuleFactory, NormalModuleFactoryRequest} from './webpack';
214

225
function escapeRegExp(str: string): string {
236
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
247
}
258

26-
279
export interface PathsPluginOptions {
10+
nmf: NormalModuleFactory;
2811
tsConfigPath: string;
2912
compilerOptions?: ts.CompilerOptions;
3013
compilerHost?: ts.CompilerHost;
3114
}
3215

3316
export class PathsPlugin implements Tapable {
17+
private _nmf: NormalModuleFactory;
3418
private _tsConfigPath: string;
3519
private _compilerOptions: ts.CompilerOptions;
3620
private _host: ts.CompilerHost;
37-
38-
source: string;
39-
target: string;
40-
41-
private mappings: any;
42-
4321
private _absoluteBaseUrl: string;
22+
private _mappings: any[] = [];
4423

4524
private static _loadOptionsFromTsConfig(tsConfigPath: string, host?: ts.CompilerHost):
4625
ts.CompilerOptions {
@@ -76,15 +55,13 @@ export class PathsPlugin implements Tapable {
7655
this._host = ts.createCompilerHost(this._compilerOptions, false);
7756
}
7857

79-
this.source = 'described-resolve';
80-
this.target = 'resolve';
81-
8258
this._absoluteBaseUrl = path.resolve(
8359
path.dirname(this._tsConfigPath),
8460
this._compilerOptions.baseUrl || '.'
8561
);
8662

87-
this.mappings = [];
63+
this._nmf = options.nmf;
64+
8865
let paths = this._compilerOptions.paths || {};
8966
Object.keys(paths).forEach(alias => {
9067
let onlyModule = alias.indexOf('*') === -1;
@@ -99,7 +76,7 @@ export class PathsPlugin implements Tapable {
9976
aliasPattern = new RegExp(`^${withStarCapturing}`);
10077
}
10178

102-
this.mappings.push({
79+
this._mappings.push({
10380
onlyModule,
10481
alias,
10582
aliasPattern,
@@ -109,66 +86,36 @@ export class PathsPlugin implements Tapable {
10986
});
11087
}
11188

112-
apply(resolver: ResolverPlugin): void {
113-
let baseUrl = this._compilerOptions.baseUrl || '.';
114-
115-
if (baseUrl) {
116-
resolver.apply(new ModulesInRootPlugin('module', this._absoluteBaseUrl, 'resolve'));
117-
}
118-
119-
this.mappings.forEach((mapping: any) => {
120-
resolver.plugin(this.source, this.createPlugin(resolver, mapping));
121-
});
122-
}
123-
124-
resolve(resolver: ResolverPlugin, mapping: any, request: any, callback: Callback<any>): any {
125-
let innerRequest = getInnerRequest(resolver, request);
126-
if (!innerRequest) {
127-
return callback();
128-
}
129-
130-
let match = innerRequest.match(mapping.aliasPattern);
131-
if (!match) {
132-
return callback();
133-
}
89+
apply(): void {
90+
this._nmf.plugin('before-resolve', (request: NormalModuleFactoryRequest,
91+
callback: Callback<any>) => {
92+
for (let mapping of this._mappings) {
93+
const match = request.request.match(mapping.aliasPattern);
94+
if (!match) { continue; }
13495

135-
let newRequestStr = mapping.target;
136-
if (!mapping.onlyModule) {
137-
newRequestStr = newRequestStr.replace('*', match[1]);
138-
}
139-
if (newRequestStr[0] === '.') {
140-
newRequestStr = path.resolve(this._absoluteBaseUrl, newRequestStr);
141-
}
142-
143-
let newRequest = Object.assign({}, request, {
144-
request: newRequestStr
145-
}) as Request;
146-
147-
return resolver.doResolve(
148-
this.target,
149-
newRequest,
150-
`aliased with mapping '${innerRequest}': '${mapping.alias}' to '${newRequestStr}'`,
151-
createInnerCallback(
152-
function(err, result) {
153-
if (arguments.length > 0) {
154-
return callback(err, result);
155-
}
156-
157-
// don't allow other aliasing or raw request
158-
callback(null, null);
159-
},
160-
callback
161-
)
162-
);
163-
}
96+
let newRequestStr = mapping.target;
97+
if (!mapping.onlyModule) {
98+
newRequestStr = newRequestStr.replace('*', match[1]);
99+
}
164100

165-
createPlugin(resolver: ResolverPlugin, mapping: any): any {
166-
return (request: any, callback: Callback<any>) => {
167-
try {
168-
this.resolve(resolver, mapping, request, callback);
169-
} catch (err) {
170-
callback(err);
101+
const moduleResolver: ts.ResolvedModuleWithFailedLookupLocations =
102+
ts.nodeModuleNameResolver(
103+
newRequestStr,
104+
this._absoluteBaseUrl,
105+
this._compilerOptions,
106+
this._host
107+
);
108+
const moduleFilePath = moduleResolver.resolvedModule ?
109+
moduleResolver.resolvedModule.resolvedFileName : '';
110+
111+
if (moduleFilePath) {
112+
return callback(null, Object.assign({}, request, {
113+
request: moduleFilePath.includes('.d.ts') ? newRequestStr : moduleFilePath
114+
}));
115+
}
171116
}
172-
};
117+
118+
return callback(null, request);
119+
});
173120
}
174121
}

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

+4
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,11 @@ export class AotPlugin implements Tapable {
341341
cb();
342342
}
343343
});
344+
});
345+
346+
compiler.plugin('normal-module-factory', (nmf: any) => {
344347
compiler.resolvers.normal.apply(new PathsPlugin({
348+
nmf,
345349
tsConfigPath: this._tsConfigPath,
346350
compilerOptions: this._compilerOptions,
347351
compilerHost: this._compilerHost

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

+12
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ export interface NormalModule {
3939
resource: string;
4040
}
4141

42+
export interface NormalModuleFactory {
43+
plugin(
44+
event: string,
45+
callback: (data: NormalModuleFactoryRequest, callback: Callback<any>) => void
46+
): any;
47+
}
48+
49+
export interface NormalModuleFactoryRequest {
50+
request: string;
51+
contextInfo: { issuer: string };
52+
}
53+
4254
export interface LoaderContext {
4355
_module: NormalModule;
4456

tests/e2e/tests/build/ts-paths.ts

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ export default function() {
1313
],
1414
'@shared/*': [
1515
'app/shared/*'
16+
],
17+
'*': [
18+
'*',
19+
'app/shared/*'
1620
]
1721
};
1822
})
@@ -25,12 +29,14 @@ export default function() {
2529
import { meaning } from 'app/shared/meaning';
2630
import { meaning as meaning2 } from '@shared';
2731
import { meaning as meaning3 } from '@shared/meaning';
32+
import { meaning as meaning4 } from 'meaning';
2833
2934
// need to use imports otherwise they are ignored and
3035
// no error is outputted, even if baseUrl/paths don't work
3136
console.log(meaning)
3237
console.log(meaning2)
3338
console.log(meaning3)
39+
console.log(meaning4)
3440
`))
3541
.then(() => ng('build'));
3642
}

0 commit comments

Comments
 (0)