From b0d2356c2619eddbfb09fc6e7b52a8f03a2b1eaf Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 08:20:23 +0000 Subject: [PATCH] perf: avoid intermediate buffer in `fs.readFileSync` calls Using `fs.readFileSync(path, 'utf8')` instead of `fs.readFileSync(path).toString()` directly decodes the stream into a string in Node.js, completely avoiding the allocation of an intermediate memory `Buffer` object and reducing GC overhead. Co-authored-by: vishnu-madhavan-git <237662584+vishnu-madhavan-git@users.noreply.github.com> --- .../cli/src/start/project/__tests__/devices-test.ts | 2 +- packages/@expo/cli/src/utils/mergeGitIgnorePaths.ts | 4 ++-- packages/@expo/config-plugins/src/android/Package.ts | 4 ++-- .../android/__tests__/renamePackageOnDisk-test.ts | 12 ++++++------ .../withAndroidSplashLegacyMainActivity-test.ts | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/@expo/cli/src/start/project/__tests__/devices-test.ts b/packages/@expo/cli/src/start/project/__tests__/devices-test.ts index 47cca6966ff94d..3eb4feb23905b1 100644 --- a/packages/@expo/cli/src/start/project/__tests__/devices-test.ts +++ b/packages/@expo/cli/src/start/project/__tests__/devices-test.ts @@ -26,7 +26,7 @@ describe('devices info', () => { const file = path.join(projectRoot, '.expo', 'devices.json'); expect(fs.existsSync(file)).toBe(true); - const { devices } = JSON.parse(fs.readFileSync(file, 'utf8').toString()); + const { devices } = JSON.parse(fs.readFileSync(file, 'utf8')); expect(devices.length).toBe(1); expect(devices[0].installationId).toBe('test-device-id'); }); diff --git a/packages/@expo/cli/src/utils/mergeGitIgnorePaths.ts b/packages/@expo/cli/src/utils/mergeGitIgnorePaths.ts index dab487df678413..8fe635d49973c9 100644 --- a/packages/@expo/cli/src/utils/mergeGitIgnorePaths.ts +++ b/packages/@expo/cli/src/utils/mergeGitIgnorePaths.ts @@ -35,8 +35,8 @@ export function mergeGitIgnorePaths( return null; } - const targetGitIgnore = fs.readFileSync(targetGitIgnorePath).toString(); - const sourceGitIgnore = fs.readFileSync(sourceGitIgnorePath).toString(); + const targetGitIgnore = fs.readFileSync(targetGitIgnorePath, 'utf8'); + const sourceGitIgnore = fs.readFileSync(sourceGitIgnorePath, 'utf8'); const merged = mergeGitIgnoreContents(targetGitIgnore, sourceGitIgnore); // Only rewrite the file if it was modified. if (merged.contents) { diff --git a/packages/@expo/config-plugins/src/android/Package.ts b/packages/@expo/config-plugins/src/android/Package.ts index 96222ebf4ba553..052004d5ed719e 100644 --- a/packages/@expo/config-plugins/src/android/Package.ts +++ b/packages/@expo/config-plugins/src/android/Package.ts @@ -125,7 +125,7 @@ export async function renameJniOnDiskForType({ filesToUpdate.forEach((filepath: string) => { try { if (fs.lstatSync(filepath).isFile() && ['.h', '.cpp'].includes(path.extname(filepath))) { - let contents = fs.readFileSync(filepath).toString(); + let contents = fs.readFileSync(filepath, 'utf8'); contents = contents.replace( new RegExp(transformJavaClassDescriptor(currentPackageName).replace(/\//g, '\\/'), 'g'), transformJavaClassDescriptor(packageName) @@ -207,7 +207,7 @@ export async function renamePackageOnDiskForType({ filesToUpdate.forEach((filepath: string) => { try { if (fs.lstatSync(filepath).isFile()) { - let contents = fs.readFileSync(filepath).toString(); + let contents = fs.readFileSync(filepath, 'utf8'); if (path.extname(filepath) === '.kt') { contents = replacePackageName(contents, currentPackageName, kotlinSanitizedPackageName); } else { diff --git a/packages/@expo/config-plugins/src/android/__tests__/renamePackageOnDisk-test.ts b/packages/@expo/config-plugins/src/android/__tests__/renamePackageOnDisk-test.ts index af4d7c87c84aa5..6aa1e4762456fb 100644 --- a/packages/@expo/config-plugins/src/android/__tests__/renamePackageOnDisk-test.ts +++ b/packages/@expo/config-plugins/src/android/__tests__/renamePackageOnDisk-test.ts @@ -44,24 +44,24 @@ public class SomeClass { await renamePackageOnDisk({ android: { package: 'xyz.bront.app' } }, '/myapp'); const mainActivityPath = '/myapp/android/app/src/main/java/xyz/bront/app/MainActivity.java'; expect(fs.existsSync(mainActivityPath)).toBeTruthy(); - expect(fs.readFileSync(mainActivityPath).toString()).toMatch('package xyz.bront.app'); + expect(fs.readFileSync(mainActivityPath, 'utf8')).toMatch('package xyz.bront.app'); const nestedClassPath = '/myapp/android/app/src/main/java/xyz/bront/app/example/SomeClass.java'; expect(fs.existsSync(nestedClassPath)).toBeTruthy(); - expect(fs.readFileSync(nestedClassPath).toString()).toMatch('package xyz.bront.app'); - expect(fs.readFileSync(nestedClassPath).toString()).not.toMatch('com.lololol'); + expect(fs.readFileSync(nestedClassPath, 'utf8')).toMatch('package xyz.bront.app'); + expect(fs.readFileSync(nestedClassPath, 'utf8')).not.toMatch('com.lololol'); const buckPath = '/myapp/android/app/BUCK'; - expect(fs.readFileSync(buckPath).toString()).toMatch('package = "xyz.bront.app"'); - expect(fs.readFileSync(buckPath).toString()).not.toMatch('com.lololol'); + expect(fs.readFileSync(buckPath, 'utf8')).toMatch('package = "xyz.bront.app"'); + expect(fs.readFileSync(buckPath, 'utf8')).not.toMatch('com.lololol'); }); it('does not clobber itself if package has similar parts', async () => { await renamePackageOnDisk({ android: { package: 'com.bront' } }, '/myapp'); const mainActivityPath = '/myapp/android/app/src/main/java/com/bront/MainActivity.java'; expect(fs.existsSync(mainActivityPath)).toBeTruthy(); - expect(fs.readFileSync(mainActivityPath).toString()).toMatch('package com.bront'); + expect(fs.readFileSync(mainActivityPath, 'utf8')).toMatch('package com.bront'); }); }); }); diff --git a/packages/@expo/prebuild-config/src/plugins/unversioned/expo-splash-screen/__tests__/withAndroidSplashLegacyMainActivity-test.ts b/packages/@expo/prebuild-config/src/plugins/unversioned/expo-splash-screen/__tests__/withAndroidSplashLegacyMainActivity-test.ts index edbcea2fa9eb34..9eaaa5e6efcfff 100644 --- a/packages/@expo/prebuild-config/src/plugins/unversioned/expo-splash-screen/__tests__/withAndroidSplashLegacyMainActivity-test.ts +++ b/packages/@expo/prebuild-config/src/plugins/unversioned/expo-splash-screen/__tests__/withAndroidSplashLegacyMainActivity-test.ts @@ -28,7 +28,7 @@ describe(setSplashScreenLegacyMainActivity, () => { }, }; const mainActivity = await AndroidConfig.Paths.getMainActivityAsync('/app'); - let contents = fs.readFileSync(mainActivity.path).toString(); + let contents = fs.readFileSync(mainActivity.path, 'utf8'); contents = await setSplashScreenLegacyMainActivity( exp, { backgroundColor: '#000020', resizeMode: 'native' },