Skip to content

Commit

Permalink
fix(@ngtools/webpack): fix module detection with reexports
Browse files Browse the repository at this point in the history
Fix #7925
  • Loading branch information
filipesilva authored and hansl committed Oct 26, 2017
1 parent 1abd7b0 commit 9f02eef
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { transformTypescript } from './ast_helpers';
import { exportNgFactory } from './export_ngfactory';

describe('@ngtools/webpack transformers', () => {
describe('replace_resources', () => {
it('should replace resources', () => {
describe('export_ngfactory', () => {
it('should export the ngfactory', () => {
const input = stripIndent`
export { AppModule } from './app/app.module';
`;
Expand All @@ -15,8 +15,24 @@ describe('@ngtools/webpack transformers', () => {
export { AppModule } from './app/app.module';
`;

const transformOpsCb = (sourceFile: ts.SourceFile) =>
exportNgFactory(sourceFile, { path: '/app.module', className: 'AppModule' });
const transformOpsCb = (sourceFile: ts.SourceFile) => exportNgFactory(sourceFile,
{ path: '/project/src/app/app.module', className: 'AppModule' });
const result = transformTypescript(input, transformOpsCb);

expect(oneLine`${result}`).toEqual(oneLine`${output}`);
});

it('should export the ngfactory when there is a barrel file', () => {
const input = stripIndent`
export { AppModule } from './app';
`;
const output = stripIndent`
export { AppModuleNgFactory } from "./app/app.module.ngfactory";
export { AppModule } from './app';
`;

const transformOpsCb = (sourceFile: ts.SourceFile) => exportNgFactory(sourceFile,
{ path: '/project/src/app/app.module', className: 'AppModule' });
const result = transformTypescript(input, transformOpsCb);

expect(oneLine`${result}`).toEqual(oneLine`${output}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ignoreDep typescript
import * as ts from 'typescript';
import { relative, dirname } from 'path';

import { findAstNodes, getFirstNode } from './ast_helpers';
import { TransformOperation, AddNodeOperation } from './make_transform';
Expand All @@ -19,6 +20,9 @@ export function exportNgFactory(
return [];
}

const relativeEntryModulePath = relative(dirname(sourceFile.fileName), entryModule.path);
const normalizedEntryModulePath = `./${relativeEntryModulePath}`.replace(/\\/g, '/');

// Get the module path from the import.
let modulePath: string;
entryModuleIdentifiers.forEach((entryModuleIdentifier) => {
Expand All @@ -37,7 +41,7 @@ export function exportNgFactory(

// Add the transform operations.
const factoryClassName = entryModule.className + 'NgFactory';
const factoryModulePath = modulePath + '.ngfactory';
const factoryModulePath = normalizedEntryModulePath + '.ngfactory';

const namedExports = ts.createNamedExports([ts.createExportSpecifier(undefined,
ts.createIdentifier(factoryClassName))]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,45 @@ describe('@ngtools/webpack transformers', () => {
`;
// tslint:enable:max-line-length

const transformOpsCb = (sourceFile: ts.SourceFile) =>
replaceBootstrap(sourceFile, { path: '/app.module', className: 'AppModule' });
const transformOpsCb = (sourceFile: ts.SourceFile) => replaceBootstrap(sourceFile,
{ path: '/project/src/app/app.module', className: 'AppModule' });
const result = transformTypescript(input, transformOpsCb);

expect(oneLine`${result}`).toEqual(oneLine`${output}`);
});

it('should replace bootstrap when barrel files are used', () => {
const input = stripIndent`
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
`;

// tslint:disable:max-line-length
const output = stripIndent`
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import * as __NgCli_bootstrap_1 from "./app/app.module.ngfactory";
import * as __NgCli_bootstrap_2 from "@angular/platform-browser";
if (environment.production) {
enableProdMode();
}
__NgCli_bootstrap_2.platformBrowser().bootstrapModuleFactory(__NgCli_bootstrap_1.AppModuleNgFactory);
`;
// tslint:enable:max-line-length

const transformOpsCb = (sourceFile: ts.SourceFile) => replaceBootstrap(sourceFile,
{ path: '/project/src/app/app.module', className: 'AppModule' });
const result = transformTypescript(input, transformOpsCb);

expect(oneLine`${result}`).toEqual(oneLine`${output}`);
Expand Down
28 changes: 5 additions & 23 deletions packages/@ngtools/webpack/src/transformers/replace_bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ignoreDep typescript
import * as ts from 'typescript';
import { relative, dirname } from 'path';

import { findAstNodes } from './ast_helpers';
import { insertStarImport } from './insert_import';
Expand All @@ -16,7 +17,7 @@ export function replaceBootstrap(
): TransformOperation[] {
const ops: TransformOperation[] = [];

// Find all identifiers using the entry module class name.
// Find all identifiers.
const entryModuleIdentifiers = findAstNodes<ts.Identifier>(null, sourceFile,
ts.SyntaxKind.Identifier, true)
.filter(identifier => identifier.getText() === entryModule.className);
Expand All @@ -25,27 +26,8 @@ export function replaceBootstrap(
return [];
}

// Get the module path from the import.
let modulePath: string;
entryModuleIdentifiers.forEach((entryModuleIdentifier) => {
// TODO: only supports `import {A, B, C} from 'modulePath'` atm, add other import support later.
if (entryModuleIdentifier.parent.kind !== ts.SyntaxKind.ImportSpecifier) {
return;
}

const importSpec = entryModuleIdentifier.parent as ts.ImportSpecifier;
const moduleSpecifier = importSpec.parent.parent.parent.moduleSpecifier;

if (moduleSpecifier.kind !== ts.SyntaxKind.StringLiteral) {
return;
}

modulePath = (moduleSpecifier as ts.StringLiteral).text;
});

if (!modulePath) {
return [];
}
const relativeEntryModulePath = relative(dirname(sourceFile.fileName), entryModule.path);
const normalizedEntryModulePath = `./${relativeEntryModulePath}`.replace(/\\/g, '/');

// Find the bootstrap calls.
const removedEntryModuleIdentifiers: ts.Identifier[] = [];
Expand Down Expand Up @@ -89,7 +71,7 @@ export function replaceBootstrap(

// Add the transform operations.
const factoryClassName = entryModule.className + 'NgFactory';
const factoryModulePath = modulePath + '.ngfactory';
const factoryModulePath = normalizedEntryModulePath + '.ngfactory';
ops.push(
// Replace the entry module import.
...insertStarImport(sourceFile, idNgFactory, factoryModulePath),
Expand Down

0 comments on commit 9f02eef

Please sign in to comment.