Skip to content

Commit 2954d1b

Browse files
gkalpakalxhub
authored andcommitted
refactor(ivy): ngcc - only try to process the necessary properties (angular#32052)
This change basically moves some checks to happen up front and ensures we don't try to process any more properties than we absolutely need. (The properties would not be processed before either, but we would consider them, before finding out that they have already been processed or that they do not exist in the entry-point's `package.json`.) This change should make no difference in the work done by `ngcc`, but it transforms the code in a way that makes the actual work known earlier, thus making it easier to parallelize the processing of each property in the future. PR Close angular#32052
1 parent 3077c9a commit 2954d1b

File tree

1 file changed

+86
-37
lines changed
  • packages/compiler-cli/ngcc/src

1 file changed

+86
-37
lines changed

packages/compiler-cli/ngcc/src/main.ts

Lines changed: 86 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -102,58 +102,67 @@ export function mainNgcc(
102102
const entryPoints = getEntryPoints(
103103
fileSystem, config, logger, resolver, absBasePath, targetEntryPointPath, pathMappings,
104104
supportedPropertiesToConsider, compileAllFormats);
105+
105106
for (const entryPoint of entryPoints) {
106107
// Are we compiling the Angular core?
107108
const isCore = entryPoint.name === '@angular/core';
108109

109-
const compiledFormats = new Set<string>();
110110
const entryPointPackageJson = entryPoint.packageJson;
111111
const entryPointPackageJsonPath = fileSystem.resolve(entryPoint.path, 'package.json');
112-
const pathToPropsMap = getFormatPathToPropertiesMap(entryPointPackageJson);
112+
const {propertiesToProcess, propertyToPropertiesToMarkAsProcessed} =
113+
getPropertiesToProcessAndMarkAsProcessed(
114+
entryPointPackageJson, supportedPropertiesToConsider);
113115

116+
let hasAnyProcessedFormat = false;
114117
let processDts = !hasBeenProcessed(entryPointPackageJson, 'typings');
115118

116-
for (const property of supportedPropertiesToConsider) {
119+
for (const property of propertiesToProcess) {
117120
// If we only need one format processed and we already have one, exit the loop.
118-
if (!compileAllFormats && (compiledFormats.size > 0)) break;
121+
if (!compileAllFormats && hasAnyProcessedFormat) break;
119122

120123
const formatPath = entryPointPackageJson[property];
121124
const format = getEntryPointFormat(fileSystem, entryPoint, property);
122125

123-
// No format then this property is not supposed to be compiled.
124-
if (!formatPath || !format) continue;
126+
// All properties listed in `propertiesToProcess` are guaranteed to point to a format-path
127+
// (i.e. they exist in `entryPointPackageJson`). Furthermore, they are also guaranteed to be
128+
// among `SUPPORTED_FORMAT_PROPERTIES`.
129+
// Based on the above, `formatPath` should always be defined and `getEntryPointFormat()`
130+
// should always return a format here (and not `undefined`).
131+
if (!formatPath || !format) {
132+
// This should never happen.
133+
throw new Error(
134+
`Invariant violated: No format-path or format for ${entryPoint.path} : ${property} ` +
135+
`(formatPath: ${formatPath} | format: ${format})`);
136+
}
125137

126138
// The `formatPath` which the property maps to is already processed - nothing to do.
127139
if (hasBeenProcessed(entryPointPackageJson, property)) {
128-
compiledFormats.add(formatPath);
140+
hasAnyProcessedFormat = true;
129141
logger.debug(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
130142
continue;
131143
}
132144

145+
const bundle = makeEntryPointBundle(
146+
fileSystem, entryPoint, formatPath, isCore, property, format, processDts, pathMappings,
147+
true);
133148

134-
if (!compiledFormats.has(formatPath)) {
135-
const bundle = makeEntryPointBundle(
136-
fileSystem, entryPoint, formatPath, isCore, property, format, processDts, pathMappings,
137-
true);
138-
139-
logger.info(`Compiling ${entryPoint.name} : ${property} as ${format}`);
140-
const transformedFiles = transformer.transform(bundle);
141-
fileWriter.writeBundle(entryPoint, bundle, transformedFiles);
142-
compiledFormats.add(formatPath);
143-
144-
const propsToMarkAsProcessed: (EntryPointJsonProperty | 'typings')[] =
145-
pathToPropsMap.get(formatPath) !;
146-
if (processDts) {
147-
propsToMarkAsProcessed.push('typings');
148-
processDts = false;
149-
}
149+
logger.info(`Compiling ${entryPoint.name} : ${property} as ${format}`);
150+
const transformedFiles = transformer.transform(bundle);
151+
fileWriter.writeBundle(entryPoint, bundle, transformedFiles);
152+
hasAnyProcessedFormat = true;
150153

151-
markAsProcessed(
152-
fileSystem, entryPointPackageJson, entryPointPackageJsonPath, propsToMarkAsProcessed);
154+
const propsToMarkAsProcessed: (EntryPointJsonProperty | 'typings')[] =
155+
propertyToPropertiesToMarkAsProcessed.get(property) !;
156+
if (processDts) {
157+
propsToMarkAsProcessed.push('typings');
158+
processDts = false;
153159
}
160+
161+
markAsProcessed(
162+
fileSystem, entryPointPackageJson, entryPointPackageJsonPath, propsToMarkAsProcessed);
154163
}
155164

156-
if (compiledFormats.size === 0) {
165+
if (!hasAnyProcessedFormat) {
157166
throw new Error(
158167
`Failed to compile any formats for entry-point at (${entryPoint.path}). Tried ${supportedPropertiesToConsider}.`);
159168
}
@@ -288,19 +297,59 @@ function logInvalidEntryPoints(logger: Logger, invalidEntryPoints: InvalidEntryP
288297
});
289298
}
290299

291-
function getFormatPathToPropertiesMap(packageJson: EntryPointPackageJson):
292-
Map<string, EntryPointJsonProperty[]> {
293-
const map = new Map<string, EntryPointJsonProperty[]>();
300+
/**
301+
* This function computes and returns the following:
302+
* - `propertiesToProcess`: An (ordered) list of properties that exist and need to be processed,
303+
* based on the specified `propertiesToConsider`, the properties in `package.json` and their
304+
* corresponding format-paths. NOTE: Only one property per format-path needs to be processed.
305+
* - `propertyToPropertiesToMarkAsProcessed`: A mapping from each property in `propertiesToProcess`
306+
* to the list of other properties in `package.json` that need to be marked as processed as soon
307+
* as of the former being processed.
308+
*/
309+
function getPropertiesToProcessAndMarkAsProcessed(
310+
packageJson: EntryPointPackageJson, propertiesToConsider: EntryPointJsonProperty[]): {
311+
propertiesToProcess: EntryPointJsonProperty[];
312+
propertyToPropertiesToMarkAsProcessed: Map<EntryPointJsonProperty, EntryPointJsonProperty[]>;
313+
} {
314+
const formatPathsToConsider = new Set<string>();
315+
316+
const propertiesToProcess: EntryPointJsonProperty[] = [];
317+
for (const prop of propertiesToConsider) {
318+
// Ignore properties that are not in `package.json`.
319+
if (!packageJson.hasOwnProperty(prop)) continue;
320+
321+
const formatPath = packageJson[prop] !;
322+
323+
// Ignore properties that map to the same format-path as a preceding property.
324+
if (formatPathsToConsider.has(formatPath)) continue;
325+
326+
// Process this property, because it is the first one to map to this format-path.
327+
formatPathsToConsider.add(formatPath);
328+
propertiesToProcess.push(prop);
329+
}
294330

331+
const formatPathToProperties: {[formatPath: string]: EntryPointJsonProperty[]} = {};
295332
for (const prop of SUPPORTED_FORMAT_PROPERTIES) {
296-
const formatPath = packageJson[prop];
297-
if (formatPath) {
298-
if (!map.has(formatPath)) {
299-
map.set(formatPath, []);
300-
}
301-
map.get(formatPath) !.push(prop);
302-
}
333+
// Ignore properties that are not in `package.json`.
334+
if (!packageJson.hasOwnProperty(prop)) continue;
335+
336+
const formatPath = packageJson[prop] !;
337+
338+
// Ignore properties that do not map to a format-path that will be considered.
339+
if (!formatPathsToConsider.has(formatPath)) continue;
340+
341+
// Add this property to the map.
342+
const list = formatPathToProperties[formatPath] || (formatPathToProperties[formatPath] = []);
343+
list.push(prop);
344+
}
345+
346+
const propertyToPropertiesToMarkAsProcessed =
347+
new Map<EntryPointJsonProperty, EntryPointJsonProperty[]>();
348+
for (const prop of propertiesToConsider) {
349+
const formatPath = packageJson[prop] !;
350+
const propertiesToMarkAsProcessed = formatPathToProperties[formatPath];
351+
propertyToPropertiesToMarkAsProcessed.set(prop, propertiesToMarkAsProcessed);
303352
}
304353

305-
return map;
354+
return {propertiesToProcess, propertyToPropertiesToMarkAsProcessed};
306355
}

0 commit comments

Comments
 (0)