Skip to content

Commit d6cb1ce

Browse files
authored
feat: export babel and metro configs to reduce boilerplate (#600)
### Summary Currently the example app has metro and babel configs setup to work correctly in the library setup. However, the files are long and verbose - increasing the maintenance cost as the consumer needs to manually update them when we make any changes. So this moves the configs to `react-native-builder-bob` package, so users can import and use them. They still have the full flexibility to customize anything they need. ### Test plan Tested by creating an Expo app and app with native modules.
1 parent 626b83f commit d6cb1ce

File tree

11 files changed

+1081
-153
lines changed

11 files changed

+1081
-153
lines changed

packages/create-react-native-library/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import generateExampleApp, {
1414
import { spawn } from './utils/spawn';
1515
import { version } from '../package.json';
1616

17-
const FALLBACK_BOB_VERSION = '0.26.0';
17+
const FALLBACK_BOB_VERSION = '0.28.0';
1818

1919
const BINARIES = [
2020
/(gradlew|\.(jar|keystore|png|jpg|gif))$/,

packages/create-react-native-library/src/utils/generateExampleApp.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ export default async function generateExampleApp({
187187
});
188188

189189
const PACKAGES_TO_ADD_DEV = {
190-
'babel-plugin-module-resolver': '^5.0.0',
191190
'react-native-builder-bob': `^${bobVersion}`,
192191
};
193192

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,18 @@
1-
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
21
const path = require('path');
3-
const escape = require('escape-string-regexp');
4-
const exclusionList = require('metro-config/src/defaults/exclusionList');
5-
const pak = require('../package.json');
2+
const { getDefaultConfig } = require('@react-native/metro-config');
3+
const { getConfig } = require('react-native-builder-bob/metro-config');
4+
const pkg = require('../package.json');
65

76
const root = path.resolve(__dirname, '..');
8-
const modules = Object.keys({ ...pak.peerDependencies });
97

108
/**
119
* Metro configuration
1210
* https://facebook.github.io/metro/docs/configuration
1311
*
1412
* @type {import('metro-config').MetroConfig}
1513
*/
16-
const config = {
17-
watchFolders: [root],
18-
19-
// We need to make sure that only one version is loaded for peerDependencies
20-
// So we block them at the root, and alias them to the versions in example's node_modules
21-
resolver: {
22-
blacklistRE: exclusionList(
23-
modules.map(
24-
(m) =>
25-
new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
26-
)
27-
),
28-
29-
extraNodeModules: modules.reduce((acc, name) => {
30-
acc[name] = path.join(__dirname, 'node_modules', name);
31-
return acc;
32-
}, {}),
33-
},
34-
35-
transformer: {
36-
getTransformOptions: async () => ({
37-
transform: {
38-
experimentalImportSupport: false,
39-
inlineRequires: true,
40-
},
41-
}),
42-
},
43-
};
44-
45-
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
14+
module.exports = getConfig(getDefaultConfig(__dirname), {
15+
root,
16+
pkg,
17+
project: __dirname,
18+
});
Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,16 @@
11
const path = require('path');
2-
const pak = require('../package.json');
2+
const { getConfig } = require('react-native-builder-bob/babel-config');
3+
const pkg = require('../package.json');
34

45
const root = path.resolve(__dirname, '..');
56

67
module.exports = function (api) {
78
api.cache(true);
89

9-
return {
10-
overrides: [
11-
{
12-
exclude: path.join(root, 'src'),
13-
presets: ['babel-preset-expo'],
14-
},
15-
{
16-
include: path.join(root, 'src'),
17-
presets: [
18-
[
19-
'module:react-native-builder-bob/babel-preset',
20-
{ modules: 'commonjs' },
21-
],
22-
],
23-
},
24-
{
25-
exclude: /\/node_modules\//,
26-
plugins: [
27-
[
28-
'module-resolver',
29-
{
30-
extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
31-
alias: {
32-
[pak.name]: path.join(root, pak.source),
33-
},
34-
},
35-
],
36-
],
37-
},
38-
],
39-
};
10+
return getConfig(
11+
{
12+
presets: ['babel-preset-expo'],
13+
},
14+
{ root, pkg }
15+
);
4016
};
Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,18 @@
11
const path = require('path');
2-
const escape = require('escape-string-regexp');
32
const { getDefaultConfig } = require('@expo/metro-config');
4-
const exclusionList = require('metro-config/src/defaults/exclusionList');
5-
const pak = require('../package.json');
3+
const { getConfig } = require('react-native-builder-bob/metro-config');
4+
const pkg = require('../package.json');
65

76
const root = path.resolve(__dirname, '..');
8-
const modules = Object.keys({ ...pak.peerDependencies });
9-
10-
const defaultConfig = getDefaultConfig(__dirname);
117

128
/**
139
* Metro configuration
1410
* https://facebook.github.io/metro/docs/configuration
1511
*
1612
* @type {import('metro-config').MetroConfig}
1713
*/
18-
const config = {
19-
...defaultConfig,
20-
21-
projectRoot: __dirname,
22-
watchFolders: [root],
23-
24-
// We need to make sure that only one version is loaded for peerDependencies
25-
// So we block them at the root, and alias them to the versions in example's node_modules
26-
resolver: {
27-
...defaultConfig.resolver,
28-
29-
blacklistRE: exclusionList(
30-
modules.map(
31-
(m) =>
32-
new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
33-
)
34-
),
35-
36-
extraNodeModules: modules.reduce((acc, name) => {
37-
acc[name] = path.join(__dirname, 'node_modules', name);
38-
return acc;
39-
}, {}),
40-
},
41-
};
42-
43-
module.exports = config;
14+
module.exports = getConfig(getDefaultConfig(__dirname), {
15+
root,
16+
pkg,
17+
project: __dirname,
18+
});
Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,12 @@
11
const path = require('path');
2-
const pak = require('../package.json');
2+
const { getConfig } = require('react-native-builder-bob/babel-config');
3+
const pkg = require('../package.json');
34

45
const root = path.resolve(__dirname, '..');
56

6-
module.exports = {
7-
overrides: [
8-
{
9-
exclude: path.join(root, 'src'),
10-
presets: ['module:@react-native/babel-preset'],
11-
},
12-
{
13-
include: path.join(root, 'src'),
14-
presets: [
15-
[
16-
'module:react-native-builder-bob/babel-preset',
17-
{ modules: 'commonjs' },
18-
],
19-
],
20-
},
21-
{
22-
exclude: /\/node_modules\//,
23-
plugins: [
24-
[
25-
'module-resolver',
26-
{
27-
extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
28-
alias: {
29-
[pak.name]: path.join(root, pak.source),
30-
},
31-
},
32-
],
33-
],
34-
},
35-
],
36-
};
7+
module.exports = getConfig(
8+
{
9+
presets: ['module:@react-native/babel-preset'],
10+
},
11+
{ root, pkg }
12+
);

packages/create-react-native-library/templates/native-common-example/example/react-native.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const path = require('path');
2-
const pak = require('../package.json');
2+
const pkg = require('../package.json');
33
<% if (example === 'test-app') { -%>
44
const { configureProjects } = require('react-native-test-app');
55
<% } -%>
@@ -23,7 +23,7 @@ module.exports = {
2323
},
2424
<% } -%>
2525
dependencies: {
26-
[pak.name]: {
26+
[pkg.name]: {
2727
root: path.join(__dirname, '..'),
2828
},
2929
},
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/* eslint-disable import/no-commonjs */
2+
3+
const path = require('path');
4+
5+
/**
6+
* Get Babel configuration for the example project.
7+
* This sets up appropriate presets and plugins for the library.
8+
* It also aliases the library to the source directory.
9+
*
10+
* @param {import('@babel/core').TransformOptions} defaultConfig Default Babel configuration
11+
* @param {object} options Options to customize the configuration
12+
* @param {string} options.root Root directory of the monorepo
13+
* @param {object} options.pkg Content of package.json of the library
14+
* @returns {import('@babel/core').TransformOptions} Babel configuration
15+
*/
16+
const getConfig = (defaultConfig, { root, pkg }) => {
17+
let src;
18+
19+
if (pkg.source.includes('/')) {
20+
const segments = pkg.source.split('/');
21+
22+
if (segments[0] === '.') {
23+
segments.shift();
24+
}
25+
26+
src = segments[0];
27+
}
28+
29+
if (src == null) {
30+
throw new Error(
31+
"Couldn't determine the source directory. Does the 'source' field in your 'package.json' point to a file within a directory?"
32+
);
33+
}
34+
35+
return {
36+
overrides: [
37+
{
38+
...defaultConfig,
39+
exclude: path.join(root, src),
40+
},
41+
{
42+
include: path.join(root, src),
43+
presets: [[require.resolve('./babel-preset'), { modules: 'commonjs' }]],
44+
},
45+
{
46+
exclude: /\/node_modules\//,
47+
plugins: [
48+
[
49+
require.resolve('babel-plugin-module-resolver'),
50+
{
51+
extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
52+
alias: {
53+
[pkg.name]: path.join(root, pkg.source),
54+
},
55+
},
56+
],
57+
],
58+
},
59+
],
60+
};
61+
};
62+
63+
exports.getConfig = getConfig;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* eslint-disable import/no-commonjs */
2+
3+
const path = require('path');
4+
const escape = require('escape-string-regexp');
5+
const exclusionList = require('metro-config/src/defaults/exclusionList');
6+
7+
/**
8+
* Get Metro configuration for the example project.
9+
* This sets up appropriate root and watch folders for the library.
10+
* It also excludes conflicting modules and aliases them to the correct place.
11+
*
12+
* @param {import('metro-config').MetroConfig} defaultConfig Default Metro configuration
13+
* @param {object} options Options to customize the configuration
14+
* @param {string} options.root Root directory of the monorepo
15+
* @param {object} options.pkg Content of package.json of the library
16+
* @param {string} options.project Directory containing the example project
17+
* @returns {import('metro-config').MetroConfig} Metro configuration
18+
*/
19+
const getConfig = (defaultConfig, { root, pkg, project }) => {
20+
const modules = Object.keys({ ...pkg.peerDependencies });
21+
22+
/**
23+
* Metro configuration
24+
* https://facebook.github.io/metro/docs/configuration
25+
*
26+
* @type {import('metro-config').MetroConfig}
27+
*/
28+
return {
29+
...defaultConfig,
30+
31+
projectRoot: project,
32+
watchFolders: [root],
33+
34+
// We need to make sure that only one version is loaded for peerDependencies
35+
// So we block them at the root, and alias them to the versions in example project's node_modules
36+
resolver: {
37+
...defaultConfig.resolver,
38+
39+
blacklistRE: exclusionList(
40+
modules.map(
41+
(m) =>
42+
new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
43+
)
44+
),
45+
46+
extraNodeModules: modules.reduce((acc, name) => {
47+
acc[name] = path.join(project, 'node_modules', name);
48+
return acc;
49+
}, {}),
50+
},
51+
};
52+
};
53+
54+
exports.getConfig = getConfig;

packages/react-native-builder-bob/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
"files": [
2525
"bin",
2626
"lib",
27-
"babel-preset.js"
27+
"babel-preset.js",
28+
"metro-config.js",
29+
"babel-config.js"
2830
],
2931
"engines": {
3032
"node": ">= 18.0.0"
@@ -49,16 +51,19 @@
4951
"@babel/preset-flow": "^7.17.12",
5052
"@babel/preset-react": "^7.17.12",
5153
"@babel/preset-typescript": "^7.17.12",
54+
"babel-plugin-module-resolver": "^5.0.2",
5255
"browserslist": "^4.20.4",
5356
"cosmiconfig": "^9.0.0",
5457
"cross-spawn": "^7.0.3",
5558
"dedent": "^0.7.0",
5659
"del": "^6.1.1",
60+
"escape-string-regexp": "^4.0.0",
5761
"fs-extra": "^10.1.0",
5862
"glob": "^8.0.3",
5963
"is-git-dirty": "^2.0.1",
6064
"json5": "^2.2.1",
6165
"kleur": "^4.1.4",
66+
"metro-config": "^0.80.9",
6267
"prompts": "^2.4.2",
6368
"which": "^2.0.2",
6469
"yargs": "^17.5.1"

0 commit comments

Comments
 (0)