diff --git a/packages/core/schematics/migrations/static-queries/strategies/template_strategy/template_strategy.ts b/packages/core/schematics/migrations/static-queries/strategies/template_strategy/template_strategy.ts index 1c61347362..21d6c217ae 100644 --- a/packages/core/schematics/migrations/static-queries/strategies/template_strategy/template_strategy.ts +++ b/packages/core/schematics/migrations/static-queries/strategies/template_strategy/template_strategy.ts @@ -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 = [ diff --git a/packages/core/schematics/test/static_queries_migration_template_spec.ts b/packages/core/schematics/test/static_queries_migration_template_spec.ts index b2ce90c8cb..8cdbf8091b 100644 --- a/packages/core/schematics/test/static_queries_migration_template_spec.ts +++ b/packages/core/schematics/test/static_queries_migration_template_spec.ts @@ -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: '

', + 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); + }); }); });