Skip to content

Commit ffd6cf6

Browse files
authored
fix: eliminate race in compilation cache (#26353)
Fixes #24569
1 parent 44f9b10 commit ffd6cf6

File tree

3 files changed

+14
-3
lines changed

3 files changed

+14
-3
lines changed

packages/playwright-core/src/utils/fileUtils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616

1717
import fs from 'fs';
18+
import type { WriteFileOptions } from 'fs';
1819
import path from 'path';
1920
import { rimraf } from '../utilsBundle';
21+
import { createGuid } from './crypto';
2022

2123
export const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => fs.stat(path, err => resolve(!err)));
2224

@@ -53,3 +55,11 @@ export async function copyFileAndMakeWritable(from: string, to: string) {
5355
export function sanitizeForFilePath(s: string) {
5456
return s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-');
5557
}
58+
59+
export function writeFileSyncAtomic(aPath: string, data: Buffer | string, options: WriteFileOptions) {
60+
const dirName = path.dirname(aPath);
61+
const fileName = path.basename(aPath);
62+
const tmpPath = path.join(dirName, fileName + '-' + createGuid());
63+
fs.writeFileSync(tmpPath, data, options);
64+
fs.renameSync(tmpPath, aPath);
65+
}

packages/playwright-test/src/transform/compilationCache.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import fs from 'fs';
1818
import os from 'os';
1919
import path from 'path';
2020
import { sourceMapSupport } from '../utilsBundle';
21+
import { writeFileSyncAtomic } from 'playwright-core/lib/utils';
2122

2223
export type MemoryCache = {
2324
codePath: string;
@@ -85,8 +86,8 @@ export function getFromCompilationCache(filename: string, hash: string, moduleUr
8586
addToCache: (code: string, map: any) => {
8687
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
8788
if (map)
88-
fs.writeFileSync(sourceMapPath, JSON.stringify(map), 'utf8');
89-
fs.writeFileSync(codePath, code, 'utf8');
89+
writeFileSyncAtomic(sourceMapPath, JSON.stringify(map), 'utf8');
90+
writeFileSyncAtomic(codePath, code, 'utf8');
9091
_innerAddToCompilationCache(filename, { codePath, sourceMapPath, moduleUrl });
9192
}
9293
};

packages/playwright-test/src/transform/transform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export function transformHook(originalCode: string, filename: string, moduleUrl?
166166
const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM!]] as BabelPlugin[] : [];
167167
const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue);
168168
const { cachedCode, addToCache } = getFromCompilationCache(filename, hash, moduleUrl);
169-
if (cachedCode)
169+
if (cachedCode !== undefined)
170170
return cachedCode;
171171

172172
// We don't use any browserslist data, but babel checks it anyway.

0 commit comments

Comments
 (0)