Skip to content

Commit 4bf6ecd

Browse files
authored
fix: fix loadConfig() failing with "missing loader for extension" (#2549)
1 parent f4c64e2 commit 4bf6ecd

File tree

1 file changed

+43
-56
lines changed

1 file changed

+43
-56
lines changed

packages/cli-config/src/readConfigFromDisk.ts

Lines changed: 43 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import type {CosmiconfigResult} from 'cosmiconfig';
12
import {cosmiconfig, cosmiconfigSync} from 'cosmiconfig';
23
import {JoiError} from './errors';
34
import * as schema from './schema';
4-
import {
5+
import type {
56
UserConfig,
67
UserDependencyConfig,
78
} from '@react-native-community/cli-types';
@@ -10,14 +11,27 @@ import chalk from 'chalk';
1011

1112
/**
1213
* Places to look for the configuration file.
14+
* Note that we need different sets for CJS and ESM because the synchronous
15+
* version cannot contain `.mjs` files. Doing so will cause "Error: Missing
16+
* loader for extension" during runtime.
1317
*/
14-
const searchPlaces = [
18+
const searchPlacesForCJS = [
1519
'react-native.config.js',
1620
'react-native.config.cjs',
17-
'react-native.config.mjs',
1821
'react-native.config.ts',
19-
'react-native.config.mjs',
2022
];
23+
const searchPlaces = [...searchPlacesForCJS, 'react-native.config.mjs'];
24+
25+
function parseUserConfig(searchResult: CosmiconfigResult): UserConfig {
26+
const config = searchResult ? searchResult.config : undefined;
27+
const result = schema.projectConfig.validate(config);
28+
29+
if (result.error) {
30+
throw new JoiError(result.error);
31+
}
32+
33+
return result.value as UserConfig;
34+
}
2135

2236
/**
2337
* Reads a project configuration as defined by the user in the current
@@ -32,15 +46,7 @@ export async function readConfigFromDiskAsync(
3246
});
3347

3448
const searchResult = await explorer.search(rootFolder);
35-
36-
const config = searchResult ? searchResult.config : undefined;
37-
const result = schema.projectConfig.validate(config);
38-
39-
if (result.error) {
40-
throw new JoiError(result.error);
41-
}
42-
43-
return result.value as UserConfig;
49+
return parseUserConfig(searchResult);
4450
}
4551

4652
/**
@@ -55,31 +61,13 @@ export function readConfigFromDisk(rootFolder: string): UserConfig {
5561
});
5662

5763
const searchResult = explorer.search(rootFolder);
58-
59-
const config = searchResult ? searchResult.config : undefined;
60-
const result = schema.projectConfig.validate(config);
61-
62-
if (result.error) {
63-
throw new JoiError(result.error);
64-
}
65-
66-
return result.value as UserConfig;
64+
return parseUserConfig(searchResult);
6765
}
6866

69-
/**
70-
* Reads a dependency configuration as defined by the developer
71-
* inside `node_modules`.
72-
*/
73-
export async function readDependencyConfigFromDiskAsync(
74-
rootFolder: string,
67+
function parseDependencyConfig(
7568
dependencyName: string,
76-
): Promise<UserDependencyConfig> {
77-
const explorer = cosmiconfig('react-native', {
78-
stopDir: rootFolder,
79-
searchPlaces,
80-
});
81-
82-
const searchResult = await explorer.search(rootFolder);
69+
searchResult: CosmiconfigResult,
70+
): UserDependencyConfig {
8371
const config = searchResult ? searchResult.config : emptyDependencyConfig;
8472

8573
const result = schema.dependencyConfig.validate(config, {abortEarly: false});
@@ -93,14 +81,31 @@ export async function readDependencyConfigFromDiskAsync(
9381
)} contains invalid configuration: ${chalk.bold(
9482
validationError.message,
9583
)}.
96-
84+
9785
Please verify it's properly linked using "npx react-native config" command and contact the package maintainers about this.`),
9886
);
9987
}
10088

10189
return result.value as UserDependencyConfig;
10290
}
10391

92+
/**
93+
* Reads a dependency configuration as defined by the developer
94+
* inside `node_modules`.
95+
*/
96+
export async function readDependencyConfigFromDiskAsync(
97+
rootFolder: string,
98+
dependencyName: string,
99+
): Promise<UserDependencyConfig> {
100+
const explorer = cosmiconfig('react-native', {
101+
stopDir: rootFolder,
102+
searchPlaces,
103+
});
104+
105+
const searchResult = await explorer.search(rootFolder);
106+
return parseDependencyConfig(dependencyName, searchResult);
107+
}
108+
104109
/**
105110
* Reads a dependency configuration as defined by the developer
106111
* inside `node_modules` synchronously.
@@ -112,29 +117,11 @@ export function readDependencyConfigFromDisk(
112117
): UserDependencyConfig {
113118
const explorer = cosmiconfigSync('react-native', {
114119
stopDir: rootFolder,
115-
searchPlaces,
120+
searchPlaces: searchPlacesForCJS,
116121
});
117122

118123
const searchResult = explorer.search(rootFolder);
119-
const config = searchResult ? searchResult.config : emptyDependencyConfig;
120-
121-
const result = schema.dependencyConfig.validate(config, {abortEarly: false});
122-
123-
if (result.error) {
124-
const validationError = new JoiError(result.error);
125-
logger.warn(
126-
inlineString(`
127-
Package ${chalk.bold(
128-
dependencyName,
129-
)} contains invalid configuration: ${chalk.bold(
130-
validationError.message,
131-
)}.
132-
133-
Please verify it's properly linked using "npx react-native config" command and contact the package maintainers about this.`),
134-
);
135-
}
136-
137-
return result.value as UserDependencyConfig;
124+
return parseDependencyConfig(dependencyName, searchResult);
138125
}
139126

140127
const emptyDependencyConfig = {

0 commit comments

Comments
 (0)