perf(ngcc): use the EntryPointManifest in DirectoryWalkerEntryPointFinder (#35931)

The `DirectoryWalkerEntryPointFinder` has to traverse the
entire node_modules library everytime it executes in order to
identify the entry-points that need to be processed. This is
very time consuming (several seconds for big projects on
Windows).

This commit changes the `DirectoryWalkerEntryPointFinder` to
use the `EntryPointManifest` to store the paths to entry-points
that were found when doing this initial node_modules traversal
in a file to be reused for subsequent calls.

This dramatically speeds up ngcc processing when it has been run once
already.

PR Close #35931
This commit is contained in:
Pete Bacon Darwin
2020-03-10 10:49:17 +00:00
committed by Andrew Kushnir
parent 560542c2a8
commit ec9f4d5bc6
3 changed files with 106 additions and 26 deletions

View File

@ -10,6 +10,7 @@ import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/depende
import {Logger} from '../logging/logger';
import {NgccConfiguration} from '../packages/configuration';
import {EntryPoint, INVALID_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../packages/entry_point';
import {EntryPointManifest} from '../packages/entry_point_manifest';
import {PathMappings} from '../utils';
import {NGCC_DIRECTORY} from '../writing/new_entry_point_file_writer';
import {EntryPointFinder} from './interface';
@ -23,16 +24,28 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder {
private basePaths = getBasePaths(this.sourceDirectory, this.pathMappings);
constructor(
private fs: FileSystem, private config: NgccConfiguration, private logger: Logger,
private resolver: DependencyResolver, private sourceDirectory: AbsoluteFsPath,
private pathMappings: PathMappings|undefined) {}
private resolver: DependencyResolver, private entryPointManifest: EntryPointManifest,
private sourceDirectory: AbsoluteFsPath, private pathMappings: PathMappings|undefined) {}
/**
* Search the `sourceDirectory`, and sub-directories, using `pathMappings` as necessary, to find
* all package entry-points.
*/
findEntryPoints(): SortedEntryPointsInfo {
const unsortedEntryPoints = this.basePaths.reduce<EntryPoint[]>(
(entryPoints, basePath) => entryPoints.concat(this.walkDirectoryForEntryPoints(basePath)),
[]);
const unsortedEntryPoints: EntryPoint[] = [];
for (const basePath of this.basePaths) {
let entryPoints = this.entryPointManifest.readEntryPointsUsingManifest(basePath);
if (entryPoints === null) {
this.logger.debug(
`No manifest found for ${basePath} so walking the directories for entry-points.`);
const startTime = Date.now();
entryPoints = this.walkDirectoryForEntryPoints(basePath);
const duration = Math.round((Date.now() - startTime) / 100) / 10;
this.logger.debug(`Walking directories took ${duration}s.`);
this.entryPointManifest.writeEntryPointManifest(basePath, entryPoints);
}
unsortedEntryPoints.push(...entryPoints);
}
return this.resolver.sortEntryPointsByDependency(unsortedEntryPoints);
}

View File

@ -39,6 +39,7 @@ import {hasBeenProcessed} from './packages/build_marker';
import {NgccConfiguration} from './packages/configuration';
import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from './packages/entry_point';
import {makeEntryPointBundle} from './packages/entry_point_bundle';
import {EntryPointManifest} from './packages/entry_point_manifest';
import {Transformer} from './packages/transformer';
import {PathMappings} from './utils';
import {cleanOutdatedPackages} from './writing/cleaning/package_cleaner';
@ -153,14 +154,15 @@ export function mainNgcc(
const absBasePath = absoluteFrom(basePath);
const config = new NgccConfiguration(fileSystem, dirname(absBasePath));
const dependencyResolver = getDependencyResolver(fileSystem, logger, config, pathMappings);
const entryPointManifest = new EntryPointManifest(fileSystem, config, logger);
// Bail out early if the work is already done.
const supportedPropertiesToConsider = ensureSupportedProperties(propertiesToConsider);
const absoluteTargetEntryPointPath =
targetEntryPointPath !== undefined ? resolve(basePath, targetEntryPointPath) : null;
const finder = getEntryPointFinder(
fileSystem, logger, dependencyResolver, config, absBasePath, absoluteTargetEntryPointPath,
pathMappings);
fileSystem, logger, dependencyResolver, config, entryPointManifest, absBasePath,
absoluteTargetEntryPointPath, pathMappings);
if (finder instanceof TargetedEntryPointFinder &&
!finder.targetNeedsProcessingOrCleaning(supportedPropertiesToConsider, compileAllFormats)) {
logger.debug('The target entry-point has already been processed');
@ -376,14 +378,15 @@ function getDependencyResolver(
function getEntryPointFinder(
fs: FileSystem, logger: Logger, resolver: DependencyResolver, config: NgccConfiguration,
basePath: AbsoluteFsPath, absoluteTargetEntryPointPath: AbsoluteFsPath | null,
entryPointManifest: EntryPointManifest, basePath: AbsoluteFsPath,
absoluteTargetEntryPointPath: AbsoluteFsPath | null,
pathMappings: PathMappings | undefined): EntryPointFinder {
if (absoluteTargetEntryPointPath !== null) {
return new TargetedEntryPointFinder(
fs, config, logger, resolver, basePath, absoluteTargetEntryPointPath, pathMappings);
} else {
return new DirectoryWalkerEntryPointFinder(
fs, config, logger, resolver, basePath, pathMappings);
fs, config, logger, resolver, entryPointManifest, basePath, pathMappings);
}
}