Skip to content

Commit 9b7b2f0

Browse files
alan-agius4Keen Yee Liau
authored and
Keen Yee Liau
committed
fix(@ngtools/webpack): add local dts file as dependencies
We now add non node_modules `.d.ts` as a dependency of the main chunk. This is important under Ivy, because NG metadata is now part of the declarations files ex: ```ts export declare class FooComponent implements OnInit { constructor(); ngOnInit(): void; static ɵfac: i0.ɵɵFactoryDef<FooComponent>; static ɵcmp: i0.ɵɵComponentDefWithMeta<FooComponent, "lib-foo", never, {}, {}, never>; } ``` Previously such files were not being added as dependency and such files didn't get invalidated when changed. Closes #16920 and closes #16921
1 parent a5bc1cd commit 9b7b2f0

File tree

2 files changed

+76
-9
lines changed

2 files changed

+76
-9
lines changed

Diff for: packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts

+35
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,41 @@ describe('Browser Builder rebuilds', () => {
268268
.toPromise();
269269
});
270270

271+
it('rebuilds on transitive non node package DTS file changes', async () => {
272+
host.writeMultipleFiles({
273+
'src/interface1.d.ts': `
274+
import { Interface2 } from './interface2';
275+
export interface Interface1 extends Interface2 { }
276+
`,
277+
'src/interface2.d.ts': `
278+
import { Interface3 } from './interface3';
279+
export interface Interface2 extends Interface3 { }
280+
`,
281+
'src/interface3.d.ts': `export interface Interface3 { nbr: number; }`,
282+
});
283+
host.appendToFile('src/main.ts', `
284+
import { Interface1 } from './interface1';
285+
const something: Interface1 = { nbr: 43 };
286+
`);
287+
288+
const overrides = { watch: true };
289+
const run = await architect.scheduleTarget(target, overrides);
290+
let buildNumber = 0;
291+
await run.output
292+
.pipe(
293+
debounceTime(rebuildDebounceTime),
294+
tap(buildEvent => expect(buildEvent.success).toBe(true)),
295+
tap(() => {
296+
buildNumber++;
297+
if (buildNumber === 1) {
298+
host.appendToFile('src/interface3.d.ts', 'export declare type MyType = string;');
299+
}
300+
}),
301+
take(2),
302+
)
303+
.toPromise();
304+
});
305+
271306
it('rebuilds after errors in JIT', async () => {
272307
const origContent = virtualFs.fileBufferToString(
273308
host.scopedSync().read(normalize('src/app/app.component.ts')),

Diff for: packages/ngtools/webpack/src/angular_compiler_plugin.ts

+41-9
Original file line numberDiff line numberDiff line change
@@ -385,13 +385,44 @@ export class AngularCompilerPlugin {
385385
}
386386

387387
const newTsProgram = this._getTsProgram();
388-
if (oldTsProgram && newTsProgram) {
388+
const newProgramSourceFiles = newTsProgram?.getSourceFiles();
389+
const localDtsFiles = new Set(
390+
newProgramSourceFiles?.filter(
391+
f => f.isDeclarationFile && !this._nodeModulesRegExp.test(f.fileName),
392+
)
393+
.map(f => this._compilerHost.denormalizePath(f.fileName)),
394+
);
395+
396+
if (!oldTsProgram) {
397+
// Add all non node package dts files as depedencies when not having an old program
398+
for (const dts of localDtsFiles) {
399+
this._typeDeps.add(dts);
400+
}
401+
} else if (oldTsProgram && newProgramSourceFiles) {
389402
// The invalidation should only happen if we have an old program
390403
// as otherwise we will invalidate all the sourcefiles.
391404
const oldFiles = new Set(oldTsProgram.getSourceFiles().map(sf => sf.fileName));
392-
const newFiles = newTsProgram.getSourceFiles().filter(sf => !oldFiles.has(sf.fileName));
393-
for (const newFile of newFiles) {
394-
this._compilerHost.invalidate(newFile.fileName);
405+
const newProgramFiles = new Set(newProgramSourceFiles.map(sf => sf.fileName));
406+
407+
for (const dependency of this._typeDeps) {
408+
// Remove type dependencies of no longer existing files
409+
if (!newProgramFiles.has(forwardSlashPath(dependency))) {
410+
this._typeDeps.delete(dependency);
411+
}
412+
}
413+
414+
for (const fileName of newProgramFiles) {
415+
if (oldFiles.has(fileName)) {
416+
continue;
417+
}
418+
419+
this._compilerHost.invalidate(fileName);
420+
421+
const denormalizedFileName = this._compilerHost.denormalizePath(fileName);
422+
if (localDtsFiles.has(denormalizedFileName)) {
423+
// Add new dts file as a type depedency
424+
this._typeDeps.add(denormalizedFileName);
425+
}
395426
}
396427
}
397428

@@ -630,8 +661,7 @@ export class AngularCompilerPlugin {
630661

631662
// This function removes a source file name and all its dependencies from the set.
632663
const removeSourceFile = (fileName: string, originalModule = false) => {
633-
if (unusedSourceFileNames.has(fileName)
634-
|| (originalModule && typeDepFileNames.has(fileName))) {
664+
if (unusedSourceFileNames.has(fileName) || (originalModule && typeDepFileNames.has(fileName))) {
635665
unusedSourceFileNames.delete(fileName);
636666
if (originalModule) {
637667
typeDepFileNames.delete(fileName);
@@ -649,7 +679,7 @@ export class AngularCompilerPlugin {
649679
compilation.warnings.push(
650680
`${fileName} is part of the TypeScript compilation but it's unused.\n` +
651681
`Add only entry points to the 'files' or 'include' properties in your tsconfig.`,
652-
);
682+
);
653683
this._unusedFiles.add(fileName);
654684
// Remove the truly unused from the type dep list.
655685
typeDepFileNames.delete(fileName);
@@ -659,7 +689,9 @@ export class AngularCompilerPlugin {
659689
// These are the TS files that weren't part of the compilation modules, aren't unused, but were
660690
// part of the TS original source list.
661691
// Next build we add them to the TS entry points so that they trigger rebuilds.
662-
this._typeDeps = typeDepFileNames;
692+
for (const fileName of typeDepFileNames) {
693+
this._typeDeps.add(fileName);
694+
}
663695
}
664696

665697
// Registration hook for webpack plugin.
@@ -1233,7 +1265,7 @@ export class AngularCompilerPlugin {
12331265

12341266
for (const resource of resourceImports) {
12351267
for (const dep of this.getResourceDependencies(
1236-
this._compilerHost.denormalizePath(resource))) {
1268+
this._compilerHost.denormalizePath(resource))) {
12371269
resourceDependencies.push(dep);
12381270
}
12391271
}

0 commit comments

Comments
 (0)