Skip to content

Commit 84752fe

Browse files
authored
feat: implement Metro caching (#23)
This pull request adds support for Metro's transformation cache. It may help in cases when Metro struggles with re-transforming the same files over and over.
1 parent 1ec43ad commit 84752fe

File tree

6 files changed

+93
-886
lines changed

6 files changed

+93
-886
lines changed

.github/workflows/e2e-tests.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ jobs:
6666
node-version: '24.10.0'
6767
cache: 'pnpm'
6868

69+
- name: Metro cache
70+
uses: actions/cache@v4
71+
with:
72+
path: apps/${{ matrix.app }}/node_modules/.cache/rn-harness/metro-cache
73+
key: metro-cache-${{ hashFiles('apps/${{ matrix.app }}/node_modules/.cache/rn-harness/metro-cache/**/*') }}
74+
restore-keys: |
75+
metro-cache
76+
6977
- name: Install dependencies
7078
run: |
7179
pnpm install
@@ -169,6 +177,14 @@ jobs:
169177
node-version: '24.10.0'
170178
cache: 'pnpm'
171179

180+
- name: Metro cache
181+
uses: actions/cache@v4
182+
with:
183+
path: apps/${{ matrix.app }}/node_modules/.cache/rn-harness/metro-cache
184+
key: metro-cache-${{ hashFiles('apps/${{ matrix.app }}/node_modules/.cache/rn-harness/metro-cache/**/*') }}
185+
restore-keys: |
186+
metro-cache
187+
172188
- name: Install Watchman
173189
run: brew install watchman
174190

packages/config/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const ConfigSchema = z
1515

1616
resetEnvironmentBetweenTestFiles: z.boolean().optional().default(true),
1717
unstable__skipAlreadyIncludedModules: z.boolean().optional().default(false),
18+
unstable__enableMetroCache: z.boolean().optional().default(false),
1819

1920
// Deprecated property - used for migration detection
2021
include: z.array(z.string()).optional(),

packages/metro/src/metro-cache.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { CacheStore, MetroCache } from 'metro-cache';
2+
import type { MixedOutput, TransformResult } from 'metro';
3+
import fs from 'node:fs';
4+
import path from 'node:path';
5+
6+
const CACHE_ROOT = path.resolve(
7+
process.cwd(),
8+
'node_modules/.cache/rn-harness/metro-cache'
9+
);
10+
11+
export const getHarnessCacheStores = (): ((
12+
metroCache: MetroCache
13+
) => CacheStore<TransformResult<MixedOutput>>[]) => {
14+
return ({ FileStore }) => {
15+
fs.mkdirSync(CACHE_ROOT, { recursive: true });
16+
17+
return [
18+
new FileStore({ root: CACHE_ROOT }) as CacheStore<
19+
TransformResult<MixedOutput>
20+
>,
21+
];
22+
};
23+
};

packages/metro/src/utils.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type NotReadOnly<T> = {
2+
-readonly [K in keyof T]: T[K];
3+
};

packages/metro/src/withRnHarness.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { MetroConfig } from '@react-native/metro-config';
1+
import type { MetroConfig } from '@react-native/metro-config';
22
import { getConfig } from '@react-native-harness/config';
33
import { patchModuleSystem } from './moduleSystem';
44
import { getHarnessResolver } from './resolver';
55
import { getHarnessManifest } from './manifest';
66
import { getHarnessBabelTransformerPath } from './babel-transformer';
7+
import { getHarnessCacheStores } from './metro-cache';
8+
import type { NotReadOnly } from './utils';
79

810
const INTERNAL_CALLSITES_REGEX =
911
/(^|[\\/])(node_modules[/\\]@react-native-harness)([\\/]|$)/;
@@ -29,7 +31,7 @@ export const withRnHarness = (
2931
const harnessBabelTransformerPath =
3032
getHarnessBabelTransformerPath(metroConfig);
3133

32-
const patchedConfig: MetroConfig = {
34+
const patchedConfig: NotReadOnly<MetroConfig> = {
3335
...metroConfig,
3436
cacheVersion: 'react-native-harness',
3537
serializer: {
@@ -83,6 +85,10 @@ export const withRnHarness = (
8385
},
8486
};
8587

88+
if (harnessConfig.unstable__enableMetroCache) {
89+
patchedConfig.cacheStores = getHarnessCacheStores();
90+
}
91+
8692
if (harnessConfig.unstable__skipAlreadyIncludedModules) {
8793
patchedConfig.serializer!.customSerializer =
8894
require('./getHarnessSerializer').getHarnessSerializer();

0 commit comments

Comments
 (0)