Skip to content

Commit

Permalink
fix(@ngtools/webpack): fix paths-plugin to allow '*' as alias
Browse files Browse the repository at this point in the history
Closes #5033
  • Loading branch information
Chris Fitzgerald authored and Brocco committed May 24, 2017
1 parent e4cedbb commit 1484868
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 90 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
"diff": "^3.1.0",
"ember-cli-normalize-entity-name": "^1.0.0",
"ember-cli-string-utils": "^1.0.0",
"enhanced-resolve": "^3.1.0",
"exports-loader": "^0.6.3",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.10.0",
Expand Down
1 change: 0 additions & 1 deletion packages/@ngtools/webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
"npm": ">= 3.0.0"
},
"dependencies": {
"enhanced-resolve": "^3.1.0",
"loader-utils": "^1.0.2",
"magic-string": "^0.19.0",
"source-map": "^0.5.6"
Expand Down
123 changes: 35 additions & 88 deletions packages/@ngtools/webpack/src/paths-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,25 @@
import * as path from 'path';
import * as ts from 'typescript';
import {Request, ResolverPlugin, Callback, Tapable} from './webpack';


const ModulesInRootPlugin: new (a: string, b: string, c: string) => ResolverPlugin
= require('enhanced-resolve/lib/ModulesInRootPlugin');

interface CreateInnerCallback {
(callback: Callback<any>,
options: Callback<any>,
message?: string,
messageOptional?: string): Callback<any>;
}

const createInnerCallback: CreateInnerCallback
= require('enhanced-resolve/lib/createInnerCallback');
const getInnerRequest: (resolver: ResolverPlugin, request: Request) => string
= require('enhanced-resolve/lib/getInnerRequest');

import {Callback, Tapable, NormalModuleFactory, NormalModuleFactoryRequest} from './webpack';

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


export interface PathsPluginOptions {
nmf: NormalModuleFactory;
tsConfigPath: string;
compilerOptions?: ts.CompilerOptions;
compilerHost?: ts.CompilerHost;
}

export class PathsPlugin implements Tapable {
private _nmf: NormalModuleFactory;
private _tsConfigPath: string;
private _compilerOptions: ts.CompilerOptions;
private _host: ts.CompilerHost;

source: string;
target: string;

private mappings: any;

private _absoluteBaseUrl: string;
private _mappings: any[] = [];

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

this.source = 'described-resolve';
this.target = 'resolve';

this._absoluteBaseUrl = path.resolve(
path.dirname(this._tsConfigPath),
this._compilerOptions.baseUrl || '.'
);

this.mappings = [];
this._nmf = options.nmf;

let paths = this._compilerOptions.paths || {};
Object.keys(paths).forEach(alias => {
let onlyModule = alias.indexOf('*') === -1;
Expand All @@ -99,7 +76,7 @@ export class PathsPlugin implements Tapable {
aliasPattern = new RegExp(`^${withStarCapturing}`);
}

this.mappings.push({
this._mappings.push({
onlyModule,
alias,
aliasPattern,
Expand All @@ -109,66 +86,36 @@ export class PathsPlugin implements Tapable {
});
}

apply(resolver: ResolverPlugin): void {
let baseUrl = this._compilerOptions.baseUrl || '.';

if (baseUrl) {
resolver.apply(new ModulesInRootPlugin('module', this._absoluteBaseUrl, 'resolve'));
}

this.mappings.forEach((mapping: any) => {
resolver.plugin(this.source, this.createPlugin(resolver, mapping));
});
}

resolve(resolver: ResolverPlugin, mapping: any, request: any, callback: Callback<any>): any {
let innerRequest = getInnerRequest(resolver, request);
if (!innerRequest) {
return callback();
}

let match = innerRequest.match(mapping.aliasPattern);
if (!match) {
return callback();
}
apply(): void {
this._nmf.plugin('before-resolve', (request: NormalModuleFactoryRequest,
callback: Callback<any>) => {
for (let mapping of this._mappings) {
const match = request.request.match(mapping.aliasPattern);
if (!match) { continue; }

let newRequestStr = mapping.target;
if (!mapping.onlyModule) {
newRequestStr = newRequestStr.replace('*', match[1]);
}
if (newRequestStr[0] === '.') {
newRequestStr = path.resolve(this._absoluteBaseUrl, newRequestStr);
}

let newRequest = Object.assign({}, request, {
request: newRequestStr
}) as Request;

return resolver.doResolve(
this.target,
newRequest,
`aliased with mapping '${innerRequest}': '${mapping.alias}' to '${newRequestStr}'`,
createInnerCallback(
function(err, result) {
if (arguments.length > 0) {
return callback(err, result);
}

// don't allow other aliasing or raw request
callback(null, null);
},
callback
)
);
}
let newRequestStr = mapping.target;
if (!mapping.onlyModule) {
newRequestStr = newRequestStr.replace('*', match[1]);
}

createPlugin(resolver: ResolverPlugin, mapping: any): any {
return (request: any, callback: Callback<any>) => {
try {
this.resolve(resolver, mapping, request, callback);
} catch (err) {
callback(err);
const moduleResolver: ts.ResolvedModuleWithFailedLookupLocations =
ts.nodeModuleNameResolver(
newRequestStr,
this._absoluteBaseUrl,
this._compilerOptions,
this._host
);
const moduleFilePath = moduleResolver.resolvedModule ?
moduleResolver.resolvedModule.resolvedFileName : '';

if (moduleFilePath) {
return callback(null, Object.assign({}, request, {
request: moduleFilePath.includes('.d.ts') ? newRequestStr : moduleFilePath
}));
}
}
};

return callback(null, request);
});
}
}
4 changes: 4 additions & 0 deletions packages/@ngtools/webpack/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,11 @@ export class AotPlugin implements Tapable {
cb();
}
});
});

compiler.plugin('normal-module-factory', (nmf: any) => {
compiler.resolvers.normal.apply(new PathsPlugin({
nmf,
tsConfigPath: this._tsConfigPath,
compilerOptions: this._compilerOptions,
compilerHost: this._compilerHost
Expand Down
12 changes: 12 additions & 0 deletions packages/@ngtools/webpack/src/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ export interface NormalModule {
resource: string;
}

export interface NormalModuleFactory {
plugin(
event: string,
callback: (data: NormalModuleFactoryRequest, callback: Callback<any>) => void
): any;
}

export interface NormalModuleFactoryRequest {
request: string;
contextInfo: { issuer: string };
}

export interface LoaderContext {
_module: NormalModule;

Expand Down
6 changes: 6 additions & 0 deletions tests/e2e/tests/build/ts-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export default function() {
],
'@shared/*': [
'app/shared/*'
],
'*': [
'*',
'app/shared/*'
]
};
})
Expand All @@ -25,12 +29,14 @@ export default function() {
import { meaning } from 'app/shared/meaning';
import { meaning as meaning2 } from '@shared';
import { meaning as meaning3 } from '@shared/meaning';
import { meaning as meaning4 } from 'meaning';
// need to use imports otherwise they are ignored and
// no error is outputted, even if baseUrl/paths don't work
console.log(meaning)
console.log(meaning2)
console.log(meaning3)
console.log(meaning4)
`))
.then(() => ng('build'));
}

0 comments on commit 1484868

Please sign in to comment.