
Ngcc adds properties to the `package.json` files of the entry-points it processes to mark them as processed for a format and point to the created Ivy entry-points (in case of `--create-ivy-entry-points`). When running ngcc in parallel mode (which is the default for the standalone ngcc command), multiple formats can be processed simultaneously for the same entry-point and the order of completion is not deterministic. Previously, ngcc would append new properties at the end of the target object in `package.json` as soon as the format processing was completed. As a result, the order of properties in the resulting `package.json` (when processing multiple formats for an entry-point in parallel) was not deterministic. For tools that use file hashes for caching purposes (such as Bazel), this lead to a high probability of cache misses. This commit fixes the problem by ensuring that the position of properties added to `package.json` files is deterministic and independent of the order in which each format is processed. Jira issue: [FW-1801](https://angular-team.atlassian.net/browse/FW-1801) Fixes #34635 PR Close #34870
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
/**
|
|
* @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
|
|
*/
|
|
|
|
/// <reference types="node" />
|
|
|
|
import * as cluster from 'cluster';
|
|
|
|
import {AbsoluteFsPath} from '../../../../src/ngtsc/file_system';
|
|
import {JsonObject} from '../../packages/entry_point';
|
|
import {PackageJsonChange, PackageJsonUpdate, PackageJsonUpdater, applyChange} from '../../writing/package_json_updater';
|
|
|
|
import {sendMessageToMaster} from './utils';
|
|
|
|
|
|
/**
|
|
* A `PackageJsonUpdater` that can safely handle update operations on multiple processes.
|
|
*/
|
|
export class ClusterPackageJsonUpdater implements PackageJsonUpdater {
|
|
constructor(private delegate: PackageJsonUpdater) {}
|
|
|
|
createUpdate(): PackageJsonUpdate {
|
|
return new PackageJsonUpdate((...args) => this.writeChanges(...args));
|
|
}
|
|
|
|
writeChanges(
|
|
changes: PackageJsonChange[], packageJsonPath: AbsoluteFsPath,
|
|
preExistingParsedJson?: JsonObject): void {
|
|
if (cluster.isMaster) {
|
|
// This is the master process:
|
|
// Actually apply the changes to the file on disk.
|
|
return this.delegate.writeChanges(changes, packageJsonPath, preExistingParsedJson);
|
|
}
|
|
|
|
// This is a worker process:
|
|
// Apply the changes in-memory (if necessary) and send a message to the master process.
|
|
if (preExistingParsedJson) {
|
|
for (const [propPath, value] of changes) {
|
|
if (propPath.length === 0) {
|
|
throw new Error(`Missing property path for writing value to '${packageJsonPath}'.`);
|
|
}
|
|
|
|
// No need to take property positioning into account for in-memory representations.
|
|
applyChange(preExistingParsedJson, propPath, value, 'unimportant');
|
|
}
|
|
}
|
|
|
|
sendMessageToMaster({
|
|
type: 'update-package-json',
|
|
packageJsonPath,
|
|
changes,
|
|
});
|
|
}
|
|
}
|