Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ export class ComponentDecoratorHandler implements
template = preanalyzed;
} else {
const templateDecl = parseTemplateDeclaration(
decorator, component, containingFile, this.evaluator, this.resourceLoader,
this.defaultPreserveWhitespaces);
node, decorator, component, containingFile, this.evaluator, this.depTracker,
this.resourceLoader, this.defaultPreserveWhitespaces);
template = extractTemplate(
node, templateDecl, this.evaluator, this.depTracker, this.resourceLoader, {
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
Expand Down Expand Up @@ -353,6 +353,13 @@ export class ComponentDecoratorHandler implements
this.depTracker.addResourceDependency(node.getSourceFile(), absoluteFrom(resourceUrl));
}
} catch {
if (this.depTracker !== null) {
// The analysis of this file cannot be re-used if one of the style URLs could
// not be resolved or loaded. Future builds should re-analyze and re-attempt
// resolution/loading.
this.depTracker.recordDependencyAnalysisFailure(node.getSourceFile());
}

if (diagnostics === undefined) {
diagnostics = [];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,9 @@ function parseExtractedTemplate(
}

export function parseTemplateDeclaration(
decorator: Decorator, component: Map<string, ts.Expression>, containingFile: string,
evaluator: PartialEvaluator, resourceLoader: ResourceLoader,
defaultPreserveWhitespaces: boolean): TemplateDeclaration {
node: ClassDeclaration, decorator: Decorator, component: Map<string, ts.Expression>,
containingFile: string, evaluator: PartialEvaluator, depTracker: DependencyTracker|null,
resourceLoader: ResourceLoader, defaultPreserveWhitespaces: boolean): TemplateDeclaration {
let preserveWhitespaces: boolean = defaultPreserveWhitespaces;
if (component.has('preserveWhitespaces')) {
const expr = component.get('preserveWhitespaces')!;
Expand Down Expand Up @@ -305,6 +305,12 @@ export function parseTemplateDeclaration(
resolvedTemplateUrl: resourceUrl,
};
} catch (e) {
if (depTracker !== null) {
// The analysis of this file cannot be re-used if the template URL could
// not be resolved. Future builds should re-analyze and re-attempt resolution.
depTracker.recordDependencyAnalysisFailure(node.getSourceFile());
}

throw makeResourceNotFoundError(
templateUrl, templateUrlExpr, ResourceTypeForDiagnostics.Template);
}
Expand Down Expand Up @@ -348,7 +354,7 @@ export function preloadAndParseTemplate(
if (templatePromise !== undefined) {
return templatePromise.then(() => {
const templateDecl = parseTemplateDeclaration(
decorator, component, containingFile, evaluator, resourceLoader,
node, decorator, component, containingFile, evaluator, depTracker, resourceLoader,
defaultPreserveWhitespaces);
const template =
extractTemplate(node, templateDecl, evaluator, depTracker, resourceLoader, options);
Expand All @@ -359,12 +365,18 @@ export function preloadAndParseTemplate(
return Promise.resolve(null);
}
} catch (e) {
if (depTracker !== null) {
// The analysis of this file cannot be re-used if the template URL could
// not be resolved. Future builds should re-analyze and re-attempt resolution.
depTracker.recordDependencyAnalysisFailure(node.getSourceFile());
}

throw makeResourceNotFoundError(
templateUrl, templateUrlExpr, ResourceTypeForDiagnostics.Template);
}
} else {
const templateDecl = parseTemplateDeclaration(
decorator, component, containingFile, evaluator, resourceLoader,
node, decorator, component, containingFile, evaluator, depTracker, resourceLoader,
defaultPreserveWhitespaces);
const template =
extractTemplate(node, templateDecl, evaluator, depTracker, resourceLoader, options);
Expand Down
45 changes: 45 additions & 0 deletions packages/compiler-cli/test/ngtsc/incremental_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {ErrorCode, ngErrorCode} from '../../src/ngtsc/diagnostics';
import {runInEachFileSystem} from '../../src/ngtsc/file_system/testing';
import {loadStandardTestFiles} from '../../src/ngtsc/testing';

Expand Down Expand Up @@ -945,6 +946,50 @@ runInEachFileSystem(() => {
});
});
});

describe('missing resource files', () => {
it('should re-analyze a component if a template file becomes available later', () => {
env.write('app.ts', `
import {Component} from '@angular/core';

@Component({
selector: 'app',
templateUrl: './some-template.html',
})
export class AppComponent {}
`);

const firstDiagnostics = env.driveDiagnostics();
expect(firstDiagnostics.length).toBe(1);
expect(firstDiagnostics[0].code).toBe(ngErrorCode(ErrorCode.COMPONENT_RESOURCE_NOT_FOUND));

env.write('some-template.html', `
<span>Test</span>
`);

env.driveMain();
});

it('should re-analyze if component style file becomes available later', () => {
env.write('app.ts', `
import {Component} from '@angular/core';

@Component({
selector: 'app',
template: 'Works',
styleUrls: ['./some-style.css'],
})
export class AppComponent {}
`);

const firstDiagnostics = env.driveDiagnostics();
expect(firstDiagnostics.length).toBe(1);
expect(firstDiagnostics[0].code).toBe(ngErrorCode(ErrorCode.COMPONENT_RESOURCE_NOT_FOUND));

env.write('some-style.css', `body {}`);
env.driveMain();
});
});
});

function setupFooBarProgram(env: NgtscTestEnvironment) {
Expand Down