From 99ee7c0e5692929ee7af492213a15e2cce53cbf9 Mon Sep 17 00:00:00 2001 From: Alan Date: Tue, 26 Mar 2019 07:11:00 +0100 Subject: [PATCH] fix(@ngtools/webpack): changes in non module code are not picked up when using barrel files Fixes #13975 --- .../test/browser/rebuild_spec_large.ts | 38 +++++++++++++++++++ .../webpack/src/angular_compiler_plugin.ts | 13 ++++++- packages/ngtools/webpack/src/loader.ts | 6 ++- .../webpack/src/transformers/ast_helpers.ts | 8 +++- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts index acd6354a4aca..e7ffee024efe 100644 --- a/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts @@ -338,4 +338,42 @@ describe('Browser Builder rebuilds', () => { take(7), ).toPromise().then(done, done.fail); }); + + it('rebuilds on changes in barrel file dependency', async () => { + host.writeMultipleFiles({ + 'src/index.ts': `export * from './interface'`, + 'src/interface.ts': `export interface Foo { bar: boolean };`, + }); + host.appendToFile('src/main.ts', ` + import { Foo } from './index'; + const x: Foo = { bar: true }; + `); + + const overrides = { watch: true, aot: false }; + let buildNumber = 0; + const run = await architect.scheduleTarget(target, overrides); + await run.output.pipe( + debounceTime(1000), + tap((buildEvent) => { + buildNumber += 1; + switch (buildNumber) { + case 1: + expect(buildEvent.success).toBe(true); + host.writeMultipleFiles({ + 'src/interface.ts': `export interface Foo { + bar: boolean; + baz?: string; + };`, + }); + break; + + case 2: + expect(buildEvent.success).toBe(true); + break; + } + }), + take(2), + ).toPromise(); + await run.stop(); + }); }); diff --git a/packages/ngtools/webpack/src/angular_compiler_plugin.ts b/packages/ngtools/webpack/src/angular_compiler_plugin.ts index 67a26cf8d66d..cb6f3b7b2297 100644 --- a/packages/ngtools/webpack/src/angular_compiler_plugin.ts +++ b/packages/ngtools/webpack/src/angular_compiler_plugin.ts @@ -1047,9 +1047,18 @@ export class AngularCompilerPlugin { const host = this._compilerHost; const cache = this._moduleResolutionCache; - const esImports = collectDeepNodes(sourceFile, - ts.SyntaxKind.ImportDeclaration) + const esImports = collectDeepNodes( + sourceFile, + [ + ts.SyntaxKind.ImportDeclaration, + ts.SyntaxKind.ExportDeclaration, + ], + ) .map(decl => { + if (!decl.moduleSpecifier) { + return null; + } + const moduleName = (decl.moduleSpecifier as ts.StringLiteral).text; const resolved = ts.resolveModuleName(moduleName, resolvedFileName, options, host, cache); diff --git a/packages/ngtools/webpack/src/loader.ts b/packages/ngtools/webpack/src/loader.ts index ca6afad0794a..046b0d9d7485 100644 --- a/packages/ngtools/webpack/src/loader.ts +++ b/packages/ngtools/webpack/src/loader.ts @@ -68,7 +68,11 @@ export function ngcLoader(this: loader.LoaderContext) { if (sourceFileName.endsWith('.ts')) { result.errorDependencies.forEach(dep => this.addDependency(dep)); const dependencies = plugin.getDependencies(sourceFileName); - dependencies.forEach(dep => { + dependencies + .filter(d => d.endsWith('index.ts')) + .forEach(d => dependencies.push(...plugin.getDependencies(d))); + + [...new Set(dependencies)].forEach(dep => { plugin.updateChangedFileExtensions(path.extname(dep)); this.addDependency(dep); }); diff --git a/packages/ngtools/webpack/src/transformers/ast_helpers.ts b/packages/ngtools/webpack/src/transformers/ast_helpers.ts index 57cf11e720ad..1d3beb7a3336 100644 --- a/packages/ngtools/webpack/src/transformers/ast_helpers.ts +++ b/packages/ngtools/webpack/src/transformers/ast_helpers.ts @@ -11,10 +11,14 @@ import { WebpackCompilerHost } from '../compiler_host'; // Find all nodes from the AST in the subtree of node of SyntaxKind kind. -export function collectDeepNodes(node: ts.Node, kind: ts.SyntaxKind): T[] { +export function collectDeepNodes( + node: ts.Node, + kind: ts.SyntaxKind | ts.SyntaxKind[], +): T[] { + const kinds = Array.isArray(kind) ? kind : [kind]; const nodes: T[] = []; const helper = (child: ts.Node) => { - if (child.kind === kind) { + if (kinds.includes(child.kind)) { nodes.push(child as T); } ts.forEachChild(child, helper);