Skip to content

Commit 12ccf5f

Browse files
authored
feat: auto-apply babel plugins (#9)
The changes required for Harness to run in the app should be minimal. This pull request updates how Harness injects Babel plugins into the app. With the addition of a custom transformer, Harness can now inject them automatically, while still falling back to any predefined custom transformer. It works with both the React Native Community CLI and Expo.
1 parent 60deb15 commit 12ccf5f

10 files changed

Lines changed: 66 additions & 15 deletions

File tree

apps/playground/.babelrc.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ module.exports = function (api) {
44
return {
55
presets: [
66
['module:@react-native/babel-preset', { useTransformReactJSX: true }],
7-
'react-native-harness/babel-preset',
87
],
98
};
109
};

packages/babel-preset/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
import { rnHarnessPreset } from './preset';
1+
import { rnHarnessPreset, rnHarnessPlugins } from './preset';
22
export default rnHarnessPreset;
3+
export { rnHarnessPlugins };
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import resolveWeakPlugin from './resolve-weak-plugin';
22

3+
export const rnHarnessPlugins = [
4+
'@babel/plugin-transform-class-static-block',
5+
resolveWeakPlugin,
6+
];
7+
38
export const rnHarnessPreset = () => {
49
if (!process.env.RN_HARNESS) {
510
return {};
611
}
712

813
return {
9-
plugins: ['@babel/plugin-transform-class-static-block', resolveWeakPlugin],
14+
plugins: rnHarnessPlugins,
1015
};
1116
};

packages/metro/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
},
2020
"dependencies": {
2121
"tslib": "^2.3.0",
22-
"@react-native-harness/config": "workspace:*"
22+
"@react-native-harness/config": "workspace:*",
23+
"@react-native-harness/babel-preset": "workspace:*"
2324
},
2425
"devDependencies": {
2526
"@types/babel__core": "^7.20.5"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { BabelTransformer } from 'metro-babel-transformer';
2+
import { rnHarnessPlugins } from '@react-native-harness/babel-preset';
3+
import { MetroConfig } from '@react-native/metro-config';
4+
5+
export const getHarnessBabelTransformerPath = (
6+
metroConfig: MetroConfig
7+
): string => {
8+
const upstreamTransformerPath = metroConfig.transformer?.babelTransformerPath;
9+
10+
if (!upstreamTransformerPath || typeof upstreamTransformerPath !== 'string') {
11+
throw new Error('Upstream transformer path is not a string');
12+
}
13+
14+
process.env.RN_HARNESS_UPSTREAM_TRANSFORMER_PATH = upstreamTransformerPath;
15+
return require.resolve('./babel-transformer.js');
16+
};
17+
18+
const transform: BabelTransformer['transform'] = (args) => {
19+
const { plugins } = args;
20+
const upstreamTransformerPath =
21+
process.env.RN_HARNESS_UPSTREAM_TRANSFORMER_PATH;
22+
23+
if (!upstreamTransformerPath || typeof upstreamTransformerPath !== 'string') {
24+
throw new Error('Upstream transformer path is not a string');
25+
}
26+
27+
const upstreamTransformer = require(upstreamTransformerPath);
28+
const pluginsWithHarness = [
29+
// Checked against @babel/core's type definitions - plugins are an array of PluginItem
30+
...((plugins as unknown[]) ?? []),
31+
...rnHarnessPlugins,
32+
];
33+
34+
return upstreamTransformer.transform({
35+
...args,
36+
plugins: pluginsWithHarness,
37+
});
38+
};
39+
40+
export { transform };

packages/metro/src/withRnHarness.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { getConfig } from '@react-native-harness/config';
33
import { patchModuleSystem } from './moduleSystem';
44
import { getHarnessResolver } from './resolver';
55
import { getHarnessManifest } from './manifest';
6+
import { getHarnessBabelTransformerPath } from './babel-transformer';
67

78
export const withRnHarness = async (
89
config: MetroConfig | Promise<MetroConfig>
@@ -20,6 +21,8 @@ export const withRnHarness = async (
2021

2122
const harnessResolver = getHarnessResolver(metroConfig, harnessConfig);
2223
const harnessManifest = getHarnessManifest(harnessConfig);
24+
const harnessBabelTransformerPath =
25+
getHarnessBabelTransformerPath(metroConfig);
2326

2427
const patchedConfig: MetroConfig = {
2528
...metroConfig,
@@ -37,6 +40,10 @@ export const withRnHarness = async (
3740
blockList: undefined,
3841
resolveRequest: harnessResolver,
3942
},
43+
transformer: {
44+
...metroConfig.transformer,
45+
babelTransformerPath: harnessBabelTransformerPath,
46+
},
4047
};
4148

4249
if (harnessConfig.unstable__skipAlreadyIncludedModules) {

packages/metro/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"files": [],
44
"include": [],
55
"references": [
6+
{
7+
"path": "../babel-preset"
8+
},
69
{
710
"path": "../config"
811
},

packages/metro/tsconfig.lib.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
},
1212
"include": ["src/**/*.ts"],
1313
"references": [
14+
{
15+
"path": "../babel-preset/tsconfig.lib.json"
16+
},
1417
{
1518
"path": "../config/tsconfig.lib.json"
1619
},

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/src/docs/getting-started/quick-start.mdx

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,6 @@ const customConfig = {
6363
module.exports = withRnHarness(mergeConfig(defaultConfig, customConfig));
6464
```
6565

66-
### 3. Update Babel Configuration
67-
68-
Add the required preset to `babel.config.js`. This is needed for module mocking and bundling speedup when running tests.
69-
70-
```javascript
71-
module.exports = {
72-
presets: ['module:@react-native/babel-preset', 'react-native-harness/babel'],
73-
// Your existing Babel config
74-
};
75-
```
76-
7766
## Writing Your First Test
7867

7968
Create a test file with a `.harness.js` or `.harness.ts` extension. Import testing utilities from `react-native-harness` instead of Jest:

0 commit comments

Comments
 (0)