feat(compiler-cli): resolve generated Sass/Less files to .css inputs (#28166)

Users might have run the CSS Preprocessor tool *before* the Angular
compiler. For example, we do it that way under Bazel. This means that
the design-time reference is different from the compile-time one - the
input to the Angular compiler is a plain .css file.

We assume that the preprocessor does a trivial 1:1 mapping using the same
basename with a different extension.

PR Close #28166
This commit is contained in:
Alex Eagle 2019-01-15 13:35:28 -08:00 committed by Alex Rickabaugh
parent 6940992932
commit a58fd210e9
2 changed files with 24 additions and 2 deletions

View File

@ -19,6 +19,7 @@ import {DTS, GENERATED_FILES, isInRootDir, relativeToRootDirs} from './util';
const NODE_MODULES_PACKAGE_NAME = /node_modules\/((\w|-|\.)+|(@(\w|-|\.)+\/(\w|-|\.)+))/; const NODE_MODULES_PACKAGE_NAME = /node_modules\/((\w|-|\.)+|(@(\w|-|\.)+\/(\w|-|\.)+))/;
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/; const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
const CSS_PREPROCESSOR_EXT = /(\.scss|\.less|\.styl)$/;
export function createCompilerHost( export function createCompilerHost(
{options, tsHost = ts.createCompilerHost(options, true)}: {options, tsHost = ts.createCompilerHost(options, true)}:
@ -270,8 +271,15 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
} else if (firstChar !== '.') { } else if (firstChar !== '.') {
resourceName = `./${resourceName}`; resourceName = `./${resourceName}`;
} }
const filePathWithNgResource = let filePathWithNgResource =
this.moduleNameToFileName(addNgResourceSuffix(resourceName), containingFile); this.moduleNameToFileName(addNgResourceSuffix(resourceName), containingFile);
// If the user specified styleUrl pointing to *.scss, but the Sass compiler was run before
// Angular, then the resource may have been generated as *.css. Simply try the resolution again.
if (!filePathWithNgResource && CSS_PREPROCESSOR_EXT.test(resourceName)) {
const fallbackResourceName = resourceName.replace(CSS_PREPROCESSOR_EXT, '.css');
filePathWithNgResource =
this.moduleNameToFileName(addNgResourceSuffix(fallbackResourceName), containingFile);
}
const result = filePathWithNgResource ? stripNgResourceSuffix(filePathWithNgResource) : null; const result = filePathWithNgResource ? stripNgResourceSuffix(filePathWithNgResource) : null;
// Used under Bazel to report more specific error with remediation advice // Used under Bazel to report more specific error with remediation advice
if (!result && (this.context as any).reportMissingResource) { if (!result && (this.context as any).reportMissingResource) {

View File

@ -196,7 +196,21 @@ describe('NgCompilerHost', () => {
const host = createHost({ngHost}); const host = createHost({ngHost});
expect(host.resourceNameToFileName('a', 'b')).toBe('someResult'); expect(host.resourceNameToFileName('a', 'b')).toBe('someResult');
}); });
it('should resolve Sass imports to generated .css files', () => {
const host = createHost({files: {'tmp': {'src': {'a': {'style.css': 'h1: bold'}}}}});
expect(host.resourceNameToFileName('./a/style.scss', '/tmp/src/index.ts'))
.toBe('/tmp/src/a/style.css');
});
it('should resolve Less imports to generated .css files', () => {
const host = createHost({files: {'tmp': {'src': {'a': {'style.css': 'h1: bold'}}}}});
expect(host.resourceNameToFileName('./a/style.less', '/tmp/src/index.ts'))
.toBe('/tmp/src/a/style.css');
});
it('should resolve Stylus imports to generated .css files', () => {
const host = createHost({files: {'tmp': {'src': {'a': {'style.css': 'h1: bold'}}}}});
expect(host.resourceNameToFileName('./a/style.styl', '/tmp/src/index.ts'))
.toBe('/tmp/src/a/style.css');
});
}); });
describe('getSourceFile', () => { describe('getSourceFile', () => {