refactor(core): static-query template strategy should not parse stylesheets (#29876)

Currently the `template-strategy` for the static query migration uses the
Angular compiler in order to determine the query timing. This is problematic
as the AngularCompilerProgram also collects metadata for referenced
component stylesheets which aren't necessarily present. e.g. in a CLI
project the component can reference a Sass file. It's not guaranteed
that the standalone Angular compiler plugin supports Sass without
custom logic that is brought in by the Angular CLI webpack plugin.

In order to avoid any failures for invalid stylesheets, we just disable
normalizing of all referenced stylesheets.

PR Close #29876
This commit is contained in:
Paul Gschwendtner 2019-04-13 00:18:24 +02:00 committed by Ben Lesh
parent ca591641c7
commit c1d5fbd0ad
2 changed files with 42 additions and 1 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AotCompiler, CompileDirectiveMetadata, CompileMetadataResolver, CompileNgModuleMetadata, NgAnalyzedModules, StaticSymbol, TemplateAst, findStaticQueryIds, staticViewQueryIds} from '@angular/compiler';
import {AotCompiler, CompileDirectiveMetadata, CompileMetadataResolver, CompileNgModuleMetadata, CompileStylesheetMetadata, NgAnalyzedModules, StaticSymbol, TemplateAst, findStaticQueryIds, staticViewQueryIds} from '@angular/compiler';
import {Diagnostic, createProgram, readConfiguration} from '@angular/compiler-cli';
import {resolve} from 'path';
import * as ts from 'typescript';
@ -41,6 +41,20 @@ export class QueryTemplateStrategy implements TimingStrategy {
// this by just accessing the necessary private properties using the bracket notation.
this.compiler = (aotProgram as any)['compiler'];
this.metadataResolver = this.compiler !['_metadataResolver'];
// Modify the "DirectiveNormalizer" to not normalize any referenced external stylesheets.
// This is necessary because in CLI projects preprocessor files are commonly referenced
// and we don't want to parse them in order to extract relative style references. This
// breaks the analysis of the project because we instantiate a standalone AOT compiler
// program which does not contain the custom logic by the Angular CLI Webpack compiler plugin.
const directiveNormalizer = this.metadataResolver !['_directiveNormalizer'];
directiveNormalizer['_normalizeStylesheet'] = function(metadata: CompileStylesheetMetadata) {
return new CompileStylesheetMetadata(
{styles: metadata.styles, styleUrls: [], moduleUrl: metadata.moduleUrl !});
};
// Retrieves the analyzed modules of the current program. This data can be
// used to determine the timing for registered queries.
const analyzedModules = (aotProgram as any)['analyzedModules'] as NgAnalyzedModules;
const ngDiagnostics = [

View File

@ -488,5 +488,32 @@ describe('static-queries migration with template strategy', () => {
expect(warnOutput[0])
.toMatch(/^⮑ {3}index.ts@6:11: Content queries cannot be migrated automatically\./);
});
it('should not normalize stylesheets which are referenced in component', async() => {
writeFile('sub_dir/index.ts', `
import {Component, NgModule, ContentChild} from '@angular/core';
@Component({
template: '<p #myRef></p>',
styleUrls: ['./my-comp.scss']
})
export class MyComp {}
@NgModule({declarations: [MyComp]})
export class MyModule {}
`);
// In order to check that the stylesheet is not normalized, we add an "@import" statement
// that would be extracted by the "DirectiveNormalizer" and fail because the URL resolver
// is not able to resolve the "../shared" relative import to the SCSS file extension.
writeFile('/sub_dir/my-comp.scss', `@import '../shared'`);
writeFile('/shared.scss', `shared {}`);
spyOn(console, 'error').and.callThrough();
await runMigration();
expect(console.error).toHaveBeenCalledTimes(0);
});
});
});