Skip to content

Commit de5b0b7

Browse files
committed
feat: improve Metro caching support
1 parent 7451764 commit de5b0b7

20 files changed

Lines changed: 265 additions & 48 deletions

File tree

.github/workflows/e2e-tests.yml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ jobs:
5959
- name: Metro cache
6060
uses: actions/cache@v4
6161
with:
62-
path: apps/playground/node_modules/.cache/rn-harness/metro-cache
63-
key: metro-cache-${{ hashFiles('apps/playground/node_modules/.cache/rn-harness/metro-cache/**/*') }}
62+
path: apps/playground/.harness/metro-cache
63+
key: ${{ runner.os }}-metro-cache-${{ hashFiles('**/bun.lock', '**/bun.lockb', '**/package-lock.json', '**/npm-shrinkwrap.json', '**/pnpm-lock.yaml', '**/yarn.lock', '**/metro.config.js', '**/metro.config.cjs', '**/metro.config.mjs', '**/metro.config.ts', '**/babel.config.js', '**/babel.config.cjs', '**/babel.config.mjs', '**/babel.config.ts', '**/babel.config.json') }}
6464
restore-keys: |
65-
metro-cache
65+
${{ runner.os }}-metro-cache-
6666
6767
- name: Install dependencies
6868
run: |
@@ -131,10 +131,10 @@ jobs:
131131
- name: Metro cache
132132
uses: actions/cache@v4
133133
with:
134-
path: apps/playground/node_modules/.cache/rn-harness/metro-cache
135-
key: metro-cache-${{ hashFiles('apps/playground/node_modules/.cache/rn-harness/metro-cache/**/*') }}
134+
path: apps/playground/.harness/metro-cache
135+
key: ${{ runner.os }}-metro-cache-${{ hashFiles('**/bun.lock', '**/bun.lockb', '**/package-lock.json', '**/npm-shrinkwrap.json', '**/pnpm-lock.yaml', '**/yarn.lock', '**/metro.config.js', '**/metro.config.cjs', '**/metro.config.mjs', '**/metro.config.ts', '**/babel.config.js', '**/babel.config.cjs', '**/babel.config.mjs', '**/babel.config.ts', '**/babel.config.json') }}
136136
restore-keys: |
137-
metro-cache
137+
${{ runner.os }}-metro-cache-
138138
139139
- name: Install Watchman
140140
run: brew install watchman
@@ -220,10 +220,10 @@ jobs:
220220
- name: Metro cache
221221
uses: actions/cache@v4
222222
with:
223-
path: apps/playground/node_modules/.cache/rn-harness/metro-cache
224-
key: metro-cache-${{ hashFiles('apps/playground/node_modules/.cache/rn-harness/metro-cache/**/*') }}
223+
path: apps/playground/.harness/metro-cache
224+
key: ${{ runner.os }}-metro-cache-${{ hashFiles('**/bun.lock', '**/bun.lockb', '**/package-lock.json', '**/npm-shrinkwrap.json', '**/pnpm-lock.yaml', '**/yarn.lock', '**/metro.config.js', '**/metro.config.cjs', '**/metro.config.mjs', '**/metro.config.ts', '**/babel.config.js', '**/babel.config.cjs', '**/babel.config.mjs', '**/babel.config.ts', '**/babel.config.json') }}
225225
restore-keys: |
226-
metro-cache
226+
${{ runner.os }}-metro-cache-
227227
228228
- name: Install dependencies
229229
run: |
@@ -276,10 +276,10 @@ jobs:
276276
- name: Metro cache
277277
uses: actions/cache@v4
278278
with:
279-
path: apps/playground/node_modules/.cache/rn-harness/metro-cache
280-
key: metro-cache-${{ hashFiles('apps/playground/node_modules/.cache/rn-harness/metro-cache/**/*') }}
279+
path: apps/playground/.harness/metro-cache
280+
key: ${{ runner.os }}-metro-cache-${{ hashFiles('**/bun.lock', '**/bun.lockb', '**/package-lock.json', '**/npm-shrinkwrap.json', '**/pnpm-lock.yaml', '**/yarn.lock', '**/metro.config.js', '**/metro.config.cjs', '**/metro.config.mjs', '**/metro.config.ts', '**/babel.config.js', '**/babel.config.cjs', '**/babel.config.mjs', '**/babel.config.ts', '**/babel.config.json') }}
281281
restore-keys: |
282-
metro-cache
282+
${{ runner.os }}-metro-cache-
283283
284284
- name: Install dependencies
285285
run: |
@@ -372,10 +372,10 @@ jobs:
372372
- name: Metro cache
373373
uses: actions/cache@v4
374374
with:
375-
path: apps/playground/node_modules/.cache/rn-harness/metro-cache
376-
key: metro-cache-${{ hashFiles('apps/playground/node_modules/.cache/rn-harness/metro-cache/**/*') }}
375+
path: apps/playground/.harness/metro-cache
376+
key: ${{ runner.os }}-metro-cache-${{ hashFiles('**/bun.lock', '**/bun.lockb', '**/package-lock.json', '**/npm-shrinkwrap.json', '**/pnpm-lock.yaml', '**/yarn.lock', '**/metro.config.js', '**/metro.config.cjs', '**/metro.config.mjs', '**/metro.config.ts', '**/babel.config.js', '**/babel.config.cjs', '**/babel.config.mjs', '**/babel.config.ts', '**/babel.config.json') }}
377377
restore-keys: |
378-
metro-cache
378+
${{ runner.os }}-metro-cache-
379379
380380
- name: Install Watchman
381381
run: brew install watchman

actions/android/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ runs:
117117
elif [ -f "yarn.lock" ]; then
118118
echo "manager=yarn" >> $GITHUB_OUTPUT
119119
echo "runner=yarn " >> $GITHUB_OUTPUT
120-
elif [ -f "bun.lockb" ]; then
120+
elif [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
121121
echo "manager=bun" >> $GITHUB_OUTPUT
122122
echo "runner=bunx " >> $GITHUB_OUTPUT
123123
elif [ -f "deno.lock" ]; then

actions/ios/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ runs:
5555
elif [ -f "yarn.lock" ]; then
5656
echo "manager=yarn" >> $GITHUB_OUTPUT
5757
echo "runner=yarn " >> $GITHUB_OUTPUT
58-
elif [ -f "bun.lockb" ]; then
58+
elif [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
5959
echo "manager=bun" >> $GITHUB_OUTPUT
6060
echo "runner=bunx " >> $GITHUB_OUTPUT
6161
elif [ -f "deno.lock" ]; then

actions/web/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ runs:
4343
elif [ -f "yarn.lock" ]; then
4444
echo "manager=yarn" >> $GITHUB_OUTPUT
4545
echo "runner=yarn " >> $GITHUB_OUTPUT
46-
elif [ -f "bun.lockb" ]; then
46+
elif [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
4747
echo "manager=bun" >> $GITHUB_OUTPUT
4848
echo "runner=bunx " >> $GITHUB_OUTPUT
4949
elif [ -f "deno.lock" ]; then

packages/github-action/src/android/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ runs:
117117
elif [ -f "yarn.lock" ]; then
118118
echo "manager=yarn" >> $GITHUB_OUTPUT
119119
echo "runner=yarn " >> $GITHUB_OUTPUT
120-
elif [ -f "bun.lockb" ]; then
120+
elif [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
121121
echo "manager=bun" >> $GITHUB_OUTPUT
122122
echo "runner=bunx " >> $GITHUB_OUTPUT
123123
elif [ -f "deno.lock" ]; then

packages/github-action/src/ios/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ runs:
5555
elif [ -f "yarn.lock" ]; then
5656
echo "manager=yarn" >> $GITHUB_OUTPUT
5757
echo "runner=yarn " >> $GITHUB_OUTPUT
58-
elif [ -f "bun.lockb" ]; then
58+
elif [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
5959
echo "manager=bun" >> $GITHUB_OUTPUT
6060
echo "runner=bunx " >> $GITHUB_OUTPUT
6161
elif [ -f "deno.lock" ]; then

packages/github-action/src/web/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ runs:
4343
elif [ -f "yarn.lock" ]; then
4444
echo "manager=yarn" >> $GITHUB_OUTPUT
4545
echo "runner=yarn " >> $GITHUB_OUTPUT
46-
elif [ -f "bun.lockb" ]; then
46+
elif [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
4747
echo "manager=bun" >> $GITHUB_OUTPUT
4848
echo "runner=bunx " >> $GITHUB_OUTPUT
4949
elif [ -f "deno.lock" ]; then

packages/jest/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@react-native-harness/bridge": "workspace:*",
3838
"@react-native-harness/bundler-metro": "workspace:*",
3939
"@react-native-harness/config": "workspace:*",
40+
"@react-native-harness/metro": "workspace:*",
4041
"@react-native-harness/platforms": "workspace:*",
4142
"@react-native-harness/tools": "workspace:*",
4243
"chalk": "^4.1.2",
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import type { Config as HarnessConfig } from '@react-native-harness/config';
3+
import type { HarnessPlatform } from '@react-native-harness/platforms';
4+
5+
const mocks = vi.hoisted(() => ({
6+
isMetroCacheReusable: vi.fn(),
7+
logMetroCacheReused: vi.fn(),
8+
logMetroPrewarmCompleted: vi.fn(),
9+
}));
10+
11+
vi.mock('@react-native-harness/metro', () => ({
12+
isMetroCacheReusable: mocks.isMetroCacheReusable,
13+
}));
14+
15+
vi.mock('../logs.js', () => ({
16+
logMetroCacheReused: mocks.logMetroCacheReused,
17+
logMetroPrewarmCompleted: mocks.logMetroPrewarmCompleted,
18+
}));
19+
20+
import { maybeLogMetroCacheReuse } from '../harness.js';
21+
22+
const platform: HarnessPlatform = {
23+
name: 'ios',
24+
platformId: 'ios',
25+
runner: '/virtual/platform-runner.js',
26+
config: {},
27+
};
28+
29+
const createHarnessConfig = (
30+
overrides: Partial<HarnessConfig> = {}
31+
): HarnessConfig =>
32+
({
33+
appRegistryComponentName: 'App',
34+
webSocketPort: 8081,
35+
disableViewFlattening: false,
36+
bridgeTimeout: 5000,
37+
entryPoint: 'index.js',
38+
unstable__enableMetroCache: true,
39+
forwardClientLogs: false,
40+
...overrides,
41+
}) as HarnessConfig;
42+
43+
describe('maybeLogMetroCacheReuse', () => {
44+
beforeEach(() => {
45+
vi.clearAllMocks();
46+
mocks.isMetroCacheReusable.mockReturnValue(false);
47+
});
48+
49+
it('logs when an existing metro cache will be reused', () => {
50+
mocks.isMetroCacheReusable.mockReturnValue(true);
51+
52+
maybeLogMetroCacheReuse(createHarnessConfig(), platform, '/tmp/project');
53+
54+
expect(mocks.isMetroCacheReusable).toHaveBeenCalledWith('/tmp/project');
55+
expect(mocks.logMetroCacheReused).toHaveBeenCalledWith(platform);
56+
});
57+
58+
it('does not log when metro cache reuse is disabled', () => {
59+
maybeLogMetroCacheReuse(
60+
createHarnessConfig({ unstable__enableMetroCache: false }),
61+
platform,
62+
'/tmp/project'
63+
);
64+
65+
expect(mocks.isMetroCacheReusable).not.toHaveBeenCalled();
66+
expect(mocks.logMetroCacheReused).not.toHaveBeenCalled();
67+
});
68+
69+
it('does not log when the metro cache is absent', () => {
70+
maybeLogMetroCacheReuse(createHarnessConfig(), platform, '/tmp/project');
71+
72+
expect(mocks.logMetroCacheReused).not.toHaveBeenCalled();
73+
});
74+
});

packages/jest/src/harness.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
getMetroInstance,
1717
prewarmMetroBundle,
1818
} from '@react-native-harness/bundler-metro';
19+
import { isMetroCacheReusable } from '@react-native-harness/metro';
1920
import { createCrashArtifactWriter } from '@react-native-harness/tools';
2021
import { InitializationTimeoutError } from './errors.js';
2122
import { Config as HarnessConfig } from '@react-native-harness/config';
@@ -24,7 +25,7 @@ import {
2425
type CrashSupervisor,
2526
} from './crash-supervisor.js';
2627
import { createClientLogListener } from './client-log-handler.js';
27-
import { logMetroPrewarmCompleted } from './logs.js';
28+
import { logMetroCacheReused, logMetroPrewarmCompleted } from './logs.js';
2829

2930
export type HarnessRunTestsOptions = Exclude<TestExecutionOptions, 'platform'>;
3031

@@ -40,6 +41,19 @@ export type Harness = {
4041
crashSupervisor: CrashSupervisor;
4142
};
4243

44+
export const maybeLogMetroCacheReuse = (
45+
config: HarnessConfig,
46+
platform: HarnessPlatform,
47+
projectRoot: string
48+
): void => {
49+
if (
50+
config.unstable__enableMetroCache &&
51+
isMetroCacheReusable(projectRoot)
52+
) {
53+
logMetroCacheReused(platform);
54+
}
55+
};
56+
4357
export const waitForAppReady = async (options: {
4458
serverBridge: BridgeServer;
4559
platformInstance: HarnessPlatformRunner;
@@ -105,6 +119,7 @@ const getHarnessInternal = async (
105119
const context: HarnessContext = {
106120
platform,
107121
};
122+
maybeLogMetroCacheReuse(config, platform, projectRoot);
108123

109124
const [metroInstance, platformInstance, serverBridge] = await Promise.all([
110125
getMetroInstance({ projectRoot, harnessConfig: config }, signal),

0 commit comments

Comments
 (0)