Skip to content
Merged
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
2 changes: 1 addition & 1 deletion packages/compiler-cli/ngcc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {AsyncNgccOptions, NgccOptions, SyncNgccOptions} from './src/ngcc_options

export {ConsoleLogger} from './src/logging/console_logger';
export {Logger, LogLevel} from './src/logging/logger';
export {AsyncNgccOptions, NgccOptions, SyncNgccOptions} from './src/ngcc_options';
export {AsyncNgccOptions, clearTsConfigCache, NgccOptions, SyncNgccOptions} from './src/ngcc_options';
export {PathMappings} from './src/path_mappings';

export function process(options: AsyncNgccOptions): Promise<void>;
Expand Down
27 changes: 26 additions & 1 deletion packages/compiler-cli/ngcc/src/ngcc_options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export function getSharedSetup(options: NgccOptions): SharedSetup&RequiredNgccOp
const absBasePath = absoluteFrom(options.basePath);
const projectPath = fileSystem.dirname(absBasePath);
const tsConfig =
options.tsConfigPath !== null ? readConfiguration(options.tsConfigPath || projectPath) : null;
options.tsConfigPath !== null ? getTsConfig(options.tsConfigPath || projectPath) : null;

let {
basePath,
Expand Down Expand Up @@ -200,3 +200,28 @@ export function getSharedSetup(options: NgccOptions): SharedSetup&RequiredNgccOp
new InPlaceFileWriter(fileSystem, logger, errorOnFailedEntryPoint),
};
}

let tsConfigCache: ParsedConfiguration|null = null;
let tsConfigPathCache: string|null = null;

/**
* Get the parsed configuration object for the given `tsConfigPath`.
*
* This function will cache the previous parsed configuration object to avoid unnecessary processing
* of the tsconfig.json in the case that it is requested repeatedly.
*
* This makes the assumption, which is true as of writing, that the contents of tsconfig.json and
* its dependencies will not change during the life of the process running ngcc.
*/
function getTsConfig(tsConfigPath: string): ParsedConfiguration|null {
if (tsConfigPath !== tsConfigPathCache) {
tsConfigPathCache = tsConfigPath;
tsConfigCache = readConfiguration(tsConfigPath);
}
return tsConfigCache;
}

export function clearTsConfigCache() {
tsConfigPathCache = null;
tsConfigCache = null;
}
5 changes: 5 additions & 0 deletions packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {Folder, MockFileSystem, runInEachFileSystem, TestFile} from '../../../sr
import {loadStandardTestFiles, loadTestFiles} from '../../../test/helpers';
import {getLockFilePath} from '../../src/locking/lock_file';
import {mainNgcc} from '../../src/main';
import {clearTsConfigCache} from '../../src/ngcc_options';
import {hasBeenProcessed, markAsProcessed} from '../../src/packages/build_marker';
import {EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point';
import {EntryPointManifestFile} from '../../src/packages/entry_point_manifest';
Expand Down Expand Up @@ -41,6 +42,10 @@ runInEachFileSystem(() => {
spyOn(os, 'cpus').and.returnValue([{model: 'Mock CPU'} as any]);
});

afterEach(() => {
clearTsConfigCache();
});

it('should run ngcc without errors for esm2015', () => {
expect(() => mainNgcc({basePath: '/node_modules', propertiesToConsider: ['esm2015']}))
.not.toThrow();
Expand Down
78 changes: 78 additions & 0 deletions packages/compiler-cli/ngcc/test/ngcc_options_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';

import {clearTsConfigCache, getSharedSetup, NgccOptions} from '../src/ngcc_options';

import {MockLogger} from './helpers/mock_logger';


runInEachFileSystem(() => {
let fs: FileSystem;
let _abs: typeof absoluteFrom;
let projectPath: AbsoluteFsPath;

beforeEach(() => {
fs = getFileSystem();
_abs = absoluteFrom;
projectPath = _abs('/project');
});

describe('getSharedSetup()', () => {
let pathToProjectTsConfig: AbsoluteFsPath;
let pathToCustomTsConfig: AbsoluteFsPath;

beforeEach(() => {
clearTsConfigCache();
pathToProjectTsConfig = fs.resolve(projectPath, 'tsconfig.json');
fs.ensureDir(fs.dirname(pathToProjectTsConfig));
fs.writeFile(pathToProjectTsConfig, '{"files": ["src/index.ts"]}');
pathToCustomTsConfig = _abs('/path/to/tsconfig.json');
fs.ensureDir(fs.dirname(pathToCustomTsConfig));
fs.writeFile(pathToCustomTsConfig, '{"files": ["custom/index.ts"]}');
});

it('should load the tsconfig.json at the project root if tsConfigPath is `undefined`', () => {
const setup = getSharedSetup({...createOptions()});
expect(setup.tsConfigPath).toBeUndefined();
expect(setup.tsConfig?.rootNames).toEqual([fs.resolve(projectPath, 'src/index.ts')]);
});

it('should load a specific tsconfig.json if tsConfigPath is a string', () => {
const setup = getSharedSetup({...createOptions(), tsConfigPath: pathToCustomTsConfig});
expect(setup.tsConfigPath).toEqual(pathToCustomTsConfig);
expect(setup.tsConfig?.rootNames).toEqual([_abs('/path/to/custom/index.ts')]);
});

it('should not load a tsconfig.json if tsConfigPath is `null`', () => {
const setup = getSharedSetup({...createOptions(), tsConfigPath: null});
expect(setup.tsConfigPath).toBe(null);
expect(setup.tsConfig).toBe(null);
});
});

/**
* This function creates an object that contains the minimal required properties for NgccOptions.
*/
function createOptions(): NgccOptions {
return {
async: false,
basePath: fs.resolve(projectPath, 'node_modules'),
propertiesToConsider: ['es2015'],
compileAllFormats: false,
createNewEntryPointFormats: false,
logger: new MockLogger(),
fileSystem: getFileSystem(),
errorOnFailedEntryPoint: true,
enableI18nLegacyMessageIdFormat: true,
invalidateEntryPointManifest: false,
};
}
});