Skip to content

Commit 45a4db3

Browse files
authored
refactor: drop cosmiconfig (#802)
### Summary [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig) is no longer maintained. Apart from that, we can't support ESM configuration properly because `cosmiconfig` only supports loading it asynchronously - but we need to be able to load it synchronously in babel config. I also took a look at [lilconfig](https://github.com/antonk52/lilconfig), but it also has the same limitation. Node 20.19.0 onwards supports synchronous `require` of ESM, so this limitation is not a technical limitation. So I decided to implement config loading myself since we don't need any advanced features of these config loaders such as traversing up until they find the config. ### Test plan Tested in a sample project with both `bob build` and in the example app with metro.
1 parent bf5c337 commit 45a4db3

File tree

6 files changed

+84
-65
lines changed

6 files changed

+84
-65
lines changed

packages/react-native-builder-bob/babel-config.js

+12-24
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-require-imports, import-x/no-commonjs, no-undef */
22

33
const path = require('path');
4-
const { cosmiconfigSync } = require('cosmiconfig');
5-
const { lstatSync } = require('fs');
6-
const { name } = require('./package.json');
4+
const { loadConfig } = require('./lib/utils/loadConfig');
75

86
/**
97
* Get Babel configuration for the example project.
@@ -17,28 +15,18 @@ const { name } = require('./package.json');
1715
* @returns {import('@babel/core').TransformOptions} Babel configuration
1816
*/
1917
const getConfig = (defaultConfig, { root, pkg }) => {
20-
const explorer = cosmiconfigSync(name, {
21-
stopDir: root,
22-
searchPlaces: ['package.json', 'bob.config.cjs', 'bob.config.js'],
23-
});
18+
const result = loadConfig(root);
2419

25-
const result = explorer.search();
26-
const src = result ? result.config.source : null;
20+
if (result == null) {
21+
throw new Error(`Couldn't find a valid configuration at ${root}.`);
22+
}
23+
24+
const { source } = result.config;
2725

28-
if (src == null) {
29-
if (
30-
lstatSync(path.join(root, 'bob.config.mjs'), {
31-
throwIfNoEntry: false,
32-
}).isFile()
33-
) {
34-
throw new Error(
35-
"Found a 'bob.config.mjs' file. However, ESM syntax is currently not supported for the Babel configuration."
36-
);
37-
} else {
38-
throw new Error(
39-
"Couldn't determine the source directory. Does your config specify a 'source' field?"
40-
);
41-
}
26+
if (source == null) {
27+
throw new Error(
28+
"Couldn't determine the source directory. Does your config specify a 'source' field?"
29+
);
4230
}
4331

4432
return {
@@ -60,7 +48,7 @@ const getConfig = (defaultConfig, { root, pkg }) => {
6048
],
6149
},
6250
{
63-
include: path.join(root, src),
51+
include: path.join(root, source),
6452
presets: [
6553
[
6654
require.resolve('./babel-preset'),

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"babel-config.js"
3030
],
3131
"engines": {
32-
"node": ">= 20.0.0"
32+
"node": ">= 20.19.0"
3333
},
3434
"publishConfig": {
3535
"access": "public",
@@ -53,7 +53,6 @@
5353
"@babel/preset-typescript": "^7.24.7",
5454
"babel-plugin-module-resolver": "^5.0.2",
5555
"browserslist": "^4.20.4",
56-
"cosmiconfig": "^9.0.0",
5756
"cross-spawn": "^7.0.3",
5857
"dedent": "^0.7.0",
5958
"del": "^6.1.1",

packages/react-native-builder-bob/src/build.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export async function build(argv: Argv) {
3131
);
3232
}
3333

34-
const result = await loadConfig();
34+
const result = loadConfig(root);
3535

3636
if (!result?.config) {
3737
logger.error(

packages/react-native-builder-bob/src/init.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export async function init() {
3737
}
3838

3939
const pkg = JSON.parse(await fs.readFile(projectPackagePath, 'utf-8'));
40-
const result = await loadConfig();
40+
const result = loadConfig(root);
4141

4242
if (result?.config && pkg.devDependencies && name in pkg.devDependencies) {
4343
const { shouldContinue } = await prompts({
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,69 @@
1-
import { cosmiconfig } from 'cosmiconfig';
2-
3-
// eslint-disable-next-line @typescript-eslint/no-require-imports,import-x/no-commonjs
4-
const { name } = require('../../package.json');
5-
6-
const root = process.cwd();
7-
const explorer = cosmiconfig(name, {
8-
stopDir: root,
9-
searchPlaces: [
10-
'package.json',
11-
'bob.config.mjs',
12-
'bob.config.cjs',
13-
'bob.config.js',
14-
],
15-
});
16-
17-
export const loadConfig = async () => {
18-
return explorer.search();
1+
import { join } from 'path';
2+
import { name } from '../../package.json';
3+
4+
const searchPlaces = [
5+
'bob.config.mjs',
6+
'bob.config.cjs',
7+
'bob.config.js',
8+
'package.json',
9+
];
10+
11+
export const loadConfig = (root: string) => {
12+
for (const filename of searchPlaces) {
13+
const result = requireConfig(root, filename);
14+
15+
if (filename === 'package.json' && result != null) {
16+
if (result.content[name] != null) {
17+
return {
18+
filepath: result.filepath,
19+
config: result.content[name],
20+
};
21+
}
22+
}
23+
24+
if (result != null) {
25+
const content = result.content;
26+
27+
if (content?.__esModule) {
28+
return {
29+
filepath: result.filepath,
30+
config: content.default,
31+
};
32+
}
33+
34+
return {
35+
filepath: result.filepath,
36+
config: content,
37+
};
38+
}
39+
}
40+
41+
return undefined;
42+
};
43+
44+
const requireConfig = (root: string, filename: string) => {
45+
const filepath = join(root, filename);
46+
47+
try {
48+
// eslint-disable-next-line @typescript-eslint/no-require-imports
49+
const content = require(filepath);
50+
51+
return {
52+
filepath,
53+
content,
54+
};
55+
} catch (e) {
56+
if (
57+
typeof e === 'object' &&
58+
e != null &&
59+
'code' in e &&
60+
e.code === 'MODULE_NOT_FOUND'
61+
) {
62+
// We expect that some of the config files won't exist
63+
// So we just return undefined in that case
64+
return undefined;
65+
}
66+
67+
throw e;
68+
}
1969
};

yarn.lock

+1-19
Original file line numberDiff line numberDiff line change
@@ -5562,23 +5562,6 @@ __metadata:
55625562
languageName: node
55635563
linkType: hard
55645564

5565-
"cosmiconfig@npm:^9.0.0":
5566-
version: 9.0.0
5567-
resolution: "cosmiconfig@npm:9.0.0"
5568-
dependencies:
5569-
env-paths: ^2.2.1
5570-
import-fresh: ^3.3.0
5571-
js-yaml: ^4.1.0
5572-
parse-json: ^5.2.0
5573-
peerDependencies:
5574-
typescript: ">=4.9.5"
5575-
peerDependenciesMeta:
5576-
typescript:
5577-
optional: true
5578-
checksum: a30c424b53d442ea0bdd24cb1b3d0d8687c8dda4a17ab6afcdc439f8964438801619cdb66e8e79f63b9caa3e6586b60d8bab9ce203e72df6c5e80179b971fe8f
5579-
languageName: node
5580-
linkType: hard
5581-
55825565
"create-jest@npm:^29.7.0":
55835566
version: 29.7.0
55845567
resolution: "create-jest@npm:29.7.0"
@@ -6491,7 +6474,7 @@ __metadata:
64916474
languageName: node
64926475
linkType: hard
64936476

6494-
"env-paths@npm:^2.2.0, env-paths@npm:^2.2.1":
6477+
"env-paths@npm:^2.2.0":
64956478
version: 2.2.1
64966479
resolution: "env-paths@npm:2.2.1"
64976480
checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e
@@ -12743,7 +12726,6 @@ __metadata:
1274312726
babel-plugin-module-resolver: ^5.0.2
1274412727
browserslist: ^4.20.4
1274512728
concurrently: ^7.2.2
12746-
cosmiconfig: ^9.0.0
1274712729
cross-spawn: ^7.0.3
1274812730
dedent: ^0.7.0
1274912731
del: ^6.1.1

0 commit comments

Comments
 (0)