From 7595d8a5e11c1c8ca339922026efeca7bc43cd25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leosvel=20P=C3=A9rez=20Espinosa?= Date: Fri, 30 May 2025 22:41:45 +0200 Subject: [PATCH] fix(js): write typescript plugin cache files atomically (#31390) ## Current Behavior The `@nx/js/typescript` plugin writes cache files in a non-atomic fashion, which can result in corrupted or empty files being written. ## Expected Behavior The `@nx/js/typescript` plugin should write cache files atomically, and they should not be corrupt. It should also retry a limited amount attempts to account for temporary file locks. ## Related Issue(s) Fixes #30239 Fixes #31187 --- packages/js/src/plugins/typescript/plugin.ts | 24 ++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/js/src/plugins/typescript/plugin.ts b/packages/js/src/plugins/typescript/plugin.ts index 0122e4e807..f9e2234d92 100644 --- a/packages/js/src/plugins/typescript/plugin.ts +++ b/packages/js/src/plugins/typescript/plugin.ts @@ -17,7 +17,14 @@ import { type TargetConfiguration, } from '@nx/devkit'; import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs'; -import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; +import { + existsSync, + readdirSync, + readFileSync, + renameSync, + statSync, + unlinkSync, +} from 'node:fs'; import { basename, dirname, @@ -122,7 +129,20 @@ function readTsConfigCacheData(): Record { } function writeToCache(cachePath: string, data: T) { - writeJsonFile(cachePath, data, { spaces: 0 }); + const maxAttempts = 5; + for (let attempt = 0; attempt < maxAttempts; attempt++) { + const unique = (Math.random().toString(16) + '00000000').slice(2, 10); + const tempPath = `${cachePath}.${process.pid}.${unique}.tmp`; + try { + writeJsonFile(tempPath, data, { spaces: 0 }); + renameSync(tempPath, cachePath); + return; + } catch { + try { + unlinkSync(tempPath); + } catch {} + } + } } function writeTsConfigCache(data: Record) { writeToCache(TS_CONFIG_CACHE_PATH, {