refactor(ngcc): support running callback before writing transformed files (#36626)
This commit enhances the `CompileFn`, which is used to process each entry-point, to support running a passed-in callback (and wait for it to complete) before proceeding with writing the transformed files to disk. This functionality is currently not used. In a subsequent commit, it will be used for passing info from worker processes to the master process that will allow ngcc to recover when a worker process crashes in the middle of processing a task. PR Close #36626
This commit is contained in:
parent
16039d837e
commit
e367593a26
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {FileToWrite} from '../rendering/utils';
|
||||||
import {Task, TaskCompletedCallback, TaskQueue} from './tasks/api';
|
import {Task, TaskCompletedCallback, TaskQueue} from './tasks/api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,10 +17,12 @@ import {Task, TaskCompletedCallback, TaskQueue} from './tasks/api';
|
||||||
export type AnalyzeEntryPointsFn = () => TaskQueue;
|
export type AnalyzeEntryPointsFn = () => TaskQueue;
|
||||||
|
|
||||||
/** The type of the function that can process/compile a task. */
|
/** The type of the function that can process/compile a task. */
|
||||||
export type CompileFn = (task: Task) => void;
|
export type CompileFn<T> = (task: Task) => void|T;
|
||||||
|
|
||||||
/** The type of the function that creates the `CompileFn` function used to process tasks. */
|
/** The type of the function that creates the `CompileFn` function used to process tasks. */
|
||||||
export type CreateCompileFn = (onTaskCompleted: TaskCompletedCallback) => CompileFn;
|
export type CreateCompileFn = <T extends void|Promise<void>>(
|
||||||
|
beforeWritingFiles: (transformedFiles: FileToWrite[]) => T,
|
||||||
|
onTaskCompleted: TaskCompletedCallback) => CompileFn<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that orchestrates and executes the required work (i.e. analyzes the entry-points,
|
* A class that orchestrates and executes the required work (i.e. analyzes the entry-points,
|
||||||
|
|
|
@ -62,17 +62,18 @@ export async function startWorker(logger: Logger, createCompileFn: CreateCompile
|
||||||
}
|
}
|
||||||
|
|
||||||
const compile = createCompileFn(
|
const compile = createCompileFn(
|
||||||
|
() => {},
|
||||||
(_task, outcome, message) => sendMessageToMaster({type: 'task-completed', outcome, message}));
|
(_task, outcome, message) => sendMessageToMaster({type: 'task-completed', outcome, message}));
|
||||||
|
|
||||||
|
|
||||||
// Listen for `ProcessTaskMessage`s and process tasks.
|
// Listen for `ProcessTaskMessage`s and process tasks.
|
||||||
cluster.worker.on('message', (msg: MessageToWorker) => {
|
cluster.worker.on('message', async (msg: MessageToWorker) => {
|
||||||
try {
|
try {
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case 'process-task':
|
case 'process-task':
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`[Worker #${cluster.worker.id}] Processing task: ${stringifyTask(msg.task)}`);
|
`[Worker #${cluster.worker.id}] Processing task: ${stringifyTask(msg.task)}`);
|
||||||
return compile(msg.task);
|
return await compile(msg.task);
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`[Worker #${cluster.worker.id}] Invalid message received: ${JSON.stringify(msg)}`);
|
`[Worker #${cluster.worker.id}] Invalid message received: ${JSON.stringify(msg)}`);
|
||||||
|
|
|
@ -31,7 +31,7 @@ export function getCreateCompileFn(
|
||||||
createNewEntryPointFormats: boolean, errorOnFailedEntryPoint: boolean,
|
createNewEntryPointFormats: boolean, errorOnFailedEntryPoint: boolean,
|
||||||
enableI18nLegacyMessageIdFormat: boolean, tsConfig: ParsedConfiguration|null,
|
enableI18nLegacyMessageIdFormat: boolean, tsConfig: ParsedConfiguration|null,
|
||||||
pathMappings: PathMappings|undefined): CreateCompileFn {
|
pathMappings: PathMappings|undefined): CreateCompileFn {
|
||||||
return onTaskCompleted => {
|
return (beforeWritingFiles, onTaskCompleted) => {
|
||||||
const fileWriter = getFileWriter(
|
const fileWriter = getFileWriter(
|
||||||
fileSystem, logger, pkgJsonUpdater, createNewEntryPointFormats, errorOnFailedEntryPoint);
|
fileSystem, logger, pkgJsonUpdater, createNewEntryPointFormats, errorOnFailedEntryPoint);
|
||||||
const {Transformer} = require('../packages/transformer');
|
const {Transformer} = require('../packages/transformer');
|
||||||
|
@ -69,11 +69,20 @@ export function getCreateCompileFn(
|
||||||
logger.warn(replaceTsWithNgInErrors(
|
logger.warn(replaceTsWithNgInErrors(
|
||||||
ts.formatDiagnosticsWithColorAndContext(result.diagnostics, bundle.src.host)));
|
ts.formatDiagnosticsWithColorAndContext(result.diagnostics, bundle.src.host)));
|
||||||
}
|
}
|
||||||
fileWriter.writeBundle(bundle, result.transformedFiles, formatPropertiesToMarkAsProcessed);
|
|
||||||
|
|
||||||
logger.debug(` Successfully compiled ${entryPoint.name} : ${formatProperty}`);
|
const writeBundle = () => {
|
||||||
|
fileWriter.writeBundle(
|
||||||
|
bundle, result.transformedFiles, formatPropertiesToMarkAsProcessed);
|
||||||
|
|
||||||
onTaskCompleted(task, TaskProcessingOutcome.Processed, null);
|
logger.debug(` Successfully compiled ${entryPoint.name} : ${formatProperty}`);
|
||||||
|
onTaskCompleted(task, TaskProcessingOutcome.Processed, null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const beforeWritingResult = beforeWritingFiles(result.transformedFiles);
|
||||||
|
|
||||||
|
return (beforeWritingResult instanceof Promise) ?
|
||||||
|
beforeWritingResult.then(writeBundle) as ReturnType<typeof beforeWritingFiles>:
|
||||||
|
writeBundle();
|
||||||
} else {
|
} else {
|
||||||
const errors = replaceTsWithNgInErrors(
|
const errors = replaceTsWithNgInErrors(
|
||||||
ts.formatDiagnosticsWithColorAndContext(result.diagnostics, bundle.src.host));
|
ts.formatDiagnosticsWithColorAndContext(result.diagnostics, bundle.src.host));
|
||||||
|
|
|
@ -23,7 +23,7 @@ export abstract class SingleProcessorExecutorBase {
|
||||||
|
|
||||||
const taskQueue = analyzeEntryPoints();
|
const taskQueue = analyzeEntryPoints();
|
||||||
const onTaskCompleted = this.createTaskCompletedCallback(taskQueue);
|
const onTaskCompleted = this.createTaskCompletedCallback(taskQueue);
|
||||||
const compile = createCompileFn(onTaskCompleted);
|
const compile = createCompileFn(() => {}, onTaskCompleted);
|
||||||
|
|
||||||
// Process all tasks.
|
// Process all tasks.
|
||||||
this.logger.debug('Processing tasks...');
|
this.logger.debug('Processing tasks...');
|
||||||
|
|
|
@ -57,12 +57,12 @@ describe('startWorker()', () => {
|
||||||
|
|
||||||
it('should create the `compileFn()`', () => {
|
it('should create the `compileFn()`', () => {
|
||||||
startWorker(mockLogger, createCompileFnSpy);
|
startWorker(mockLogger, createCompileFnSpy);
|
||||||
expect(createCompileFnSpy).toHaveBeenCalledWith(jasmine.any(Function));
|
expect(createCompileFnSpy).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set up `compileFn()` to send `task-completed` messages to master', () => {
|
it('should set up `compileFn()` to send `task-completed` messages to master', () => {
|
||||||
startWorker(mockLogger, createCompileFnSpy);
|
startWorker(mockLogger, createCompileFnSpy);
|
||||||
const onTaskCompleted: TaskCompletedCallback = createCompileFnSpy.calls.argsFor(0)[0];
|
const onTaskCompleted: TaskCompletedCallback = createCompileFnSpy.calls.argsFor(0)[1];
|
||||||
|
|
||||||
onTaskCompleted(null as any, TaskProcessingOutcome.Processed, null);
|
onTaskCompleted(null as any, TaskProcessingOutcome.Processed, null);
|
||||||
expect(processSendSpy).toHaveBeenCalledTimes(1);
|
expect(processSendSpy).toHaveBeenCalledTimes(1);
|
||||||
|
|
|
@ -132,14 +132,15 @@ describe('SingleProcessExecutor', () => {
|
||||||
{allTasksCompleted: true, getNextTask: jasmine.any(Function)})]);
|
{allTasksCompleted: true, getNextTask: jasmine.any(Function)})]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass the created TaskCompletedCallback to the createCompileFn', () => {
|
it('should pass the necessary callbacks to createCompileFn', () => {
|
||||||
|
const beforeWritingFiles = jasmine.any(Function);
|
||||||
|
const onTaskCompleted = () => {};
|
||||||
const createCompileFn =
|
const createCompileFn =
|
||||||
jasmine.createSpy('createCompileFn').and.returnValue(function compileFn() {});
|
jasmine.createSpy('createCompileFn').and.returnValue(function compileFn() {});
|
||||||
function onTaskCompleted() {}
|
|
||||||
createTaskCompletedCallback.and.returnValue(onTaskCompleted);
|
createTaskCompletedCallback.and.returnValue(onTaskCompleted);
|
||||||
executor.execute(noTasks, createCompileFn);
|
executor.execute(noTasks, createCompileFn);
|
||||||
expect(createCompileFn).toHaveBeenCalledTimes(1);
|
expect(createCompileFn).toHaveBeenCalledTimes(1);
|
||||||
expect(createCompileFn).toHaveBeenCalledWith(onTaskCompleted);
|
expect(createCompileFn).toHaveBeenCalledWith(beforeWritingFiles, onTaskCompleted);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue