diff --git a/packages/@ngtools/webpack/src/transformers/export_ngfactory.spec.ts b/packages/@ngtools/webpack/src/transformers/export_ngfactory.spec.ts index 8477143fc2dc..6ee8aa9483f5 100644 --- a/packages/@ngtools/webpack/src/transformers/export_ngfactory.spec.ts +++ b/packages/@ngtools/webpack/src/transformers/export_ngfactory.spec.ts @@ -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'; `; @@ -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}`); diff --git a/packages/@ngtools/webpack/src/transformers/export_ngfactory.ts b/packages/@ngtools/webpack/src/transformers/export_ngfactory.ts index 4b46545d91ec..828f36348cb9 100644 --- a/packages/@ngtools/webpack/src/transformers/export_ngfactory.ts +++ b/packages/@ngtools/webpack/src/transformers/export_ngfactory.ts @@ -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'; @@ -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) => { @@ -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))]); diff --git a/packages/@ngtools/webpack/src/transformers/replace_bootstrap.spec.ts b/packages/@ngtools/webpack/src/transformers/replace_bootstrap.spec.ts index b353d2d479fc..2a1a828cd6ca 100644 --- a/packages/@ngtools/webpack/src/transformers/replace_bootstrap.spec.ts +++ b/packages/@ngtools/webpack/src/transformers/replace_bootstrap.spec.ts @@ -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}`); diff --git a/packages/@ngtools/webpack/src/transformers/replace_bootstrap.ts b/packages/@ngtools/webpack/src/transformers/replace_bootstrap.ts index 56aef44705b3..ec04db66ac46 100644 --- a/packages/@ngtools/webpack/src/transformers/replace_bootstrap.ts +++ b/packages/@ngtools/webpack/src/transformers/replace_bootstrap.ts @@ -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'; @@ -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(null, sourceFile, ts.SyntaxKind.Identifier, true) .filter(identifier => identifier.getText() === entryModule.className); @@ -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[] = []; @@ -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),