perf(ivy): ngcc - avoid unnecessary file-write operations when marking properties as processed (#32003)

Previously, when `ngcc` needed to mark multiple properties as processed
(e.g. a processed format property and `typings` or all supported
properties for a non-Angular entry-point), it would update each one
separately and write the file to disk multiple times.

This commit changes this, so that multiple properties can be updated at
once with one file-write operation. While this theoretically improves
performance (reducing the I/O operations), it is not expected to have
any noticeable impact in practice, since these operations are a tiny
fraction of `ngcc`'s work.

This change will be useful for a subsequent change to mark all
properties that map to the same `formatPath` as processed, once it is
processed the first time.

PR Close #32003
This commit is contained in:
George Kalpakas
2019-08-04 17:51:37 +03:00
committed by Alex Rickabaugh
parent e7e3f5d952
commit 541ce98432
4 changed files with 65 additions and 30 deletions

View File

@ -147,10 +147,11 @@ export function mainNgcc(
// Either this format was just compiled or its underlying format was compiled because of a
// previous property.
if (compiledFormats.has(formatPath)) {
markAsProcessed(fileSystem, entryPointPackageJson, entryPointPackageJsonPath, property);
if (processDts) {
markAsProcessed(fileSystem, entryPointPackageJson, entryPointPackageJsonPath, 'typings');
}
const propsToMarkAsProcessed = [property];
if (processDts) propsToMarkAsProcessed.push('typings');
markAsProcessed(
fileSystem, entryPointPackageJson, entryPointPackageJsonPath, propsToMarkAsProcessed);
}
}
@ -193,7 +194,7 @@ function getTargetedEntryPoints(
fs, config, logger, resolver, basePath, absoluteTargetEntryPointPath, pathMappings);
const entryPointInfo = finder.findEntryPoints();
if (entryPointInfo.entryPoints.length === 0) {
markNonAngularPackageAsProcessed(fs, absoluteTargetEntryPointPath, propertiesToConsider);
markNonAngularPackageAsProcessed(fs, absoluteTargetEntryPointPath);
}
return entryPointInfo;
}
@ -242,14 +243,13 @@ function hasProcessedTargetEntryPoint(
* So mark all formats in this entry-point as processed so that clients of ngcc can avoid
* triggering ngcc for this entry-point in the future.
*/
function markNonAngularPackageAsProcessed(
fs: FileSystem, path: AbsoluteFsPath, propertiesToConsider: string[]) {
function markNonAngularPackageAsProcessed(fs: FileSystem, path: AbsoluteFsPath) {
const packageJsonPath = resolve(path, 'package.json');
const packageJson = JSON.parse(fs.readFile(packageJsonPath));
propertiesToConsider.forEach(formatProperty => {
if (packageJson[formatProperty])
markAsProcessed(fs, packageJson, packageJsonPath, formatProperty as EntryPointJsonProperty);
});
// Note: We are marking all supported properties as processed, even if they don't exist in the
// `package.json` file. While this is redundant, it is also harmless.
markAsProcessed(fs, packageJson, packageJsonPath, SUPPORTED_FORMAT_PROPERTIES);
}
function logInvalidEntryPoints(logger: Logger, invalidEntryPoints: InvalidEntryPoint[]): void {

View File

@ -38,17 +38,25 @@ export function hasBeenProcessed(
}
/**
* Write a build marker for the given entry-point and format property, to indicate that it has
* Write a build marker for the given entry-point and format properties, to indicate that they have
* been compiled by this version of ngcc.
*
* @param entryPoint the entry-point to write a marker.
* @param format the property in the package.json of the format for which we are writing the marker.
* @param fs The current file-system being used.
* @param packageJson The parsed contents of the `package.json` file for the entry-point.
* @param packageJsonPath The absolute path to the `package.json` file.
* @param properties The properties in the `package.json` of the formats for which we are writing
* the marker.
*/
export function markAsProcessed(
fs: FileSystem, packageJson: EntryPointPackageJson, packageJsonPath: AbsoluteFsPath,
format: EntryPointJsonProperty) {
if (!packageJson.__processed_by_ivy_ngcc__) packageJson.__processed_by_ivy_ngcc__ = {};
packageJson.__processed_by_ivy_ngcc__[format] = NGCC_VERSION;
properties: EntryPointJsonProperty[]) {
const processed =
packageJson.__processed_by_ivy_ngcc__ || (packageJson.__processed_by_ivy_ngcc__ = {});
for (const prop of properties) {
processed[prop] = NGCC_VERSION;
}
// Just in case this package.json was synthesized due to a custom configuration
// we will ensure that the path to the containing folder exists before we write the file.
fs.ensureDir(dirname(packageJsonPath));