Skip to content

Commit

Permalink
refactor: switch from child_process to worker_threads
Browse files Browse the repository at this point in the history
- Remove unused import of `rewritePathsWithExposedFederatedModules` in `make-federated-types.ts`
- Update `compileTypesAsync` function in `compileTypesAsync.ts` to accept a `loggerHint` parameter and use the `getLogger` function from `helpers`
- Remove `compileWorker.js` file as it is no longer needed
- Update `plugin.ts` to use the updated `compileTypesAsync` function and pass the `federationConfig` parameter
  • Loading branch information
steven-pribilinskiy committed Oct 13, 2024
1 parent 3b13ae8 commit 4e54b83
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 71 deletions.
26 changes: 4 additions & 22 deletions src/bin/make-federated-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import path from 'node:path';

import parseArgs from 'minimist';

import { rewritePathsWithExposedFederatedModules } from '../compileTypes';
import { compileTypesAsync } from '../compileTypes/compileTypesAsync';
import {
DEFAULT_DIR_DIST,
Expand Down Expand Up @@ -59,26 +58,9 @@ console.log(`Emitting types for ${exposedModules.length} exposed module(s)`);
setLogger(console);

compileTypesAsync({
tsconfigPath,
exposedModules,
outFile,
federationConfig,
dirGlobalTypes,
})
.then(({ isSuccess, typeDefinitions }) => {
if (!isSuccess) {
console.error('Failed to compile types');
process.exit(1);
}

console.log('Replacing paths with names of exposed federate modules in typings file:', outFile);

rewritePathsWithExposedFederatedModules(federationConfig, outFile, typeDefinitions);

console.log(
`Asynchronous types compilation completed successfully in ${process.uptime()} seconds`,
);
})
.catch(error => {
console.error('Error during type compilation:', error);
process.exit(1);
});
outFile,
tsconfigPath,
});
6 changes: 6 additions & 0 deletions src/compileTypes/compileTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import ts from 'typescript';

import { getAllFilePaths, getLogger } from '../helpers';

import type { FederationConfig } from '../models';
import { getTSConfigCompilerOptions, reportCompileDiagnostic } from './helpers';

export type CompileTypesParams = {
tsconfigPath: string;
exposedModules: string[];
outFile: string;
dirGlobalTypes: string;
federationConfig: FederationConfig;
};

export type CompileTypesResult = {
Expand Down Expand Up @@ -63,6 +65,10 @@ export function compileTypes({
const { diagnostics, emitSkipped } = program.emit();
diagnostics.forEach(reportCompileDiagnostic);

if (emitSkipped) {
logger.log('[compileTypes]: TypeScript program emit skipped');
}

return {
isSuccess: !emitSkipped,
typeDefinitions: fileContent,
Expand Down
57 changes: 38 additions & 19 deletions src/compileTypes/compileTypesAsync.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,57 @@
import { type ChildProcess, fork } from 'node:child_process';
import path from 'node:path';
import { Worker, parentPort } from 'node:worker_threads';

import type { CompileTypesParams, CompileTypesResult } from './compileTypes';
import { getLogger } from '../helpers';
import type { CompileTypesParams } from './compileTypes';
import type { CompileTypesWorkerMessage } from './compileTypesWorker';

let currentWorker: ChildProcess | null = null;
let worker: Worker | null = null;

export function compileTypesAsync(params: CompileTypesParams, loggerHint = ''): Promise<void> {
const logger = getLogger();

export function compileTypesAsync(params: CompileTypesParams): Promise<CompileTypesResult> {
return new Promise((resolve, reject) => {
if (currentWorker) {
currentWorker.kill();
if (worker) {
logger.log('Terminating existing worker process');
worker.terminate();
}

const workerPath = path.join(__dirname, 'compileWorker.js');
currentWorker = fork(workerPath);

currentWorker.on('message', (result: CompileTypesResult) => {
resolve(result);
currentWorker?.kill();
currentWorker = null;
worker = new Worker(workerPath);

worker.on('message', (result: CompileTypesWorkerMessage) => {
switch (result.status) {
case 'success':
resolve();
break;
case 'failure':
logger.warn('[Worker]: Failed to compile types for exposed modules.', loggerHint);
reject(new Error('Failed to compile types for exposed modules.'));
break;
case 'error':
logger.warn('[Worker]: Error compiling types for exposed modules.', loggerHint);
reject(result.error);
break;
}
worker?.terminate();
worker = null;
});

currentWorker.on('error', error => {
worker.on('error', error => {
logger.warn('[Worker]: Unexpected error.', loggerHint);
logger.log(error);
reject(error);
currentWorker?.kill();
currentWorker = null;
worker?.terminate();
worker = null;
});

currentWorker.on('exit', code => {
worker.on('exit', code => {
if (code !== 0 && code !== null) {
reject(new Error(`Worker process exited with code ${code}`));
reject(new Error(`[Worker]: Process exited with code ${code}`));
}
currentWorker = null;
worker = null;
});

currentWorker.send(params);
parentPort?.postMessage({ ...params, logger });
});
}
48 changes: 48 additions & 0 deletions src/compileTypes/compileTypesWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { parentPort } from 'node:worker_threads';

import type { Compilation } from 'webpack';
import { type CompileTypesParams, compileTypes } from './compileTypes';
import { rewritePathsWithExposedFederatedModules } from './rewritePathsWithExposedFederatedModules';

type CompileTypesWorkerMessageError = {
status: 'error';
error: Error;
};

export type CompileTypesWorkerMessage =
| { status: 'success' }
| { status: 'failure' }
| CompileTypesWorkerMessageError;

parentPort?.on('message', (message: CompileTypesParams & { logger: Compilation['logger'] }) => {
const { logger, ...params } = message;

try {
const startTime = performance.now();
const { isSuccess, typeDefinitions } = compileTypes(params);

if (isSuccess) {
const endTime = performance.now();
const timeTakenInSeconds = (endTime - startTime) / 1000;
logger.log(`Types compilation completed in ${timeTakenInSeconds.toFixed(2)} seconds`);

logger.log(
`Replacing paths with names of exposed federate modules in typings file: ${params.outFile}`,
);
rewritePathsWithExposedFederatedModules(
params.federationConfig,
params.outFile,
typeDefinitions,
);

parentPort?.postMessage({ status: 'success' } satisfies CompileTypesWorkerMessage);
} else {
parentPort?.postMessage({ status: 'failure' } satisfies CompileTypesWorkerMessage);
}
} catch (error) {
parentPort?.postMessage({
status: 'error',
error: error as Error,
} satisfies CompileTypesWorkerMessageError);
}
});
5 changes: 0 additions & 5 deletions src/compileTypes/compileWorker.ts

This file was deleted.

34 changes: 9 additions & 25 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'node:path';

import type { Compiler, WebpackPluginInstance } from 'webpack';

import { compileTypesAsync, rewritePathsWithExposedFederatedModules } from './compileTypes';
import { compileTypesAsync } from './compileTypes';
import {
DEFAULT_DIR_DIST,
DEFAULT_DIR_DOWNLOADED_TYPES,
Expand Down Expand Up @@ -95,32 +95,16 @@ export class ModuleFederationTypesPlugin implements WebpackPluginInstance {

// Create types for exposed modules
const compileTypesAfterEmit = async () => {
try {
const startTime = performance.now();

const { isSuccess, typeDefinitions } = await compileTypesAsync({
compileTypesAsync(
{
tsconfigPath: TS_CONFIG_FILE,
exposedModules: exposes as string[],
outFile,
dirGlobalTypes,
});

if (isSuccess) {
const endTime = performance.now();
const timeTakenInSeconds = (endTime - startTime) / 1000;
logger.log(`Types compilation completed in ${timeTakenInSeconds.toFixed(2)} seconds`);

rewritePathsWithExposedFederatedModules(
federationPluginOptions as FederationConfig,
outFile,
typeDefinitions,
);
} else {
logger.warn('Failed to compile types for exposed modules.', getLoggerHint(compiler));
}
} catch (error) {
logger.error('Error compiling types asynchronously:', error);
}
federationConfig: federationPluginOptions as FederationConfig,
},
getLoggerHint(compiler),
);
};

// Import types from remote modules
Expand Down Expand Up @@ -178,11 +162,11 @@ export class ModuleFederationTypesPlugin implements WebpackPluginInstance {
if (exposes && !isCompilationDisabled) {
compiler.hooks.afterEmit.tap(PLUGIN_NAME, () => {
if (shouldSyncContinuously) {
logger.log('Compiling types on afterEmit event');
logger.log('Asynchronously compiling types on afterEmit event');
compileTypesContinuouslyAfterEmit();
} else if (!isCompiledOnce) {
isCompiledOnce = true;
logger.log('Compile types on startup only');
isCompiledOnce = true;
compileTypesAfterEmit();
}
});
Expand Down

0 comments on commit 4e54b83

Please sign in to comment.