-
Notifications
You must be signed in to change notification settings - Fork 24.3k
/
loadMetroConfig.js
141 lines (123 loc) · 4.13 KB
/
loadMetroConfig.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {Config} from '@react-native-community/cli-types';
import type {ConfigT, InputConfigT, YargArguments} from 'metro-config';
import {getWorkspaceRoot} from './getWorkspaceRoot';
import {reactNativePlatformResolver} from './metroPlatformResolver';
import {CLIError, logger} from '@react-native-community/cli-tools';
import {loadConfig, mergeConfig, resolveConfig} from 'metro-config';
import path from 'path';
export type {Config};
export type ConfigLoadingContext = $ReadOnly<{
root: Config['root'],
reactNativePath: Config['reactNativePath'],
platforms: Config['platforms'],
...
}>;
/**
* Get the config options to override based on RN CLI inputs.
*/
function getOverrideConfig(
ctx: ConfigLoadingContext,
config: ConfigT,
): InputConfigT {
const outOfTreePlatforms = Object.keys(ctx.platforms).filter(
platform => ctx.platforms[platform].npmPackageName,
);
const resolver: Partial<{...ConfigT['resolver']}> = {
platforms: [...Object.keys(ctx.platforms), 'native'],
};
if (outOfTreePlatforms.length) {
resolver.resolveRequest = reactNativePlatformResolver(
outOfTreePlatforms.reduce<{[platform: string]: string}>(
(result, platform) => {
result[platform] = ctx.platforms[platform].npmPackageName;
return result;
},
{},
),
config.resolver?.resolveRequest,
);
}
// Always include the project root as a watch folder, since Metro expects this
const watchFolders = [config.projectRoot];
if (typeof config.watchFolders !== 'undefined') {
watchFolders.push(...config.watchFolders);
} else {
// Fallback to inferring a workspace root
const workspaceRoot = getWorkspaceRoot(ctx.root);
if (typeof workspaceRoot === 'string') {
watchFolders.push(workspaceRoot);
}
}
const overrides: InputConfigT = {
resolver,
serializer: {
// We can include multiple copies of InitializeCore here because metro will
// only add ones that are already part of the bundle
getModulesRunBeforeMainModule: () => [
require.resolve(
path.join(ctx.reactNativePath, 'Libraries/Core/InitializeCore'),
{paths: [ctx.root]},
),
...outOfTreePlatforms.map(platform =>
require.resolve(
`${ctx.platforms[platform].npmPackageName}/Libraries/Core/InitializeCore`,
),
),
],
},
watchFolders,
};
return overrides;
}
/**
* Load Metro config.
*
* Allows the CLI to override select values in `metro.config.js` based on
* dynamic user options in `ctx`.
*/
export default async function loadMetroConfig(
ctx: ConfigLoadingContext,
options: YargArguments = {},
): Promise<ConfigT> {
const cwd = ctx.root;
const projectConfig = await resolveConfig(options.config, cwd);
if (projectConfig.isEmpty) {
throw new CLIError(`No Metro config found in ${cwd}`);
}
logger.debug(`Reading Metro config from ${projectConfig.filepath}`);
if (!global.__REACT_NATIVE_METRO_CONFIG_LOADED) {
const warning = `
=================================================================================================
From React Native 0.73, your project's Metro config should extend '@react-native/metro-config'
or it will fail to build. Please copy the template at:
https://github.com/facebook/react-native/blob/main/packages/react-native/template/metro.config.js
This warning will be removed in future (https://github.com/facebook/metro/issues/1018).
=================================================================================================
`;
for (const line of warning.trim().split('\n')) {
logger.warn(line);
}
}
const config = await loadConfig(
{
cwd,
...options,
},
{
// Enables users to explicitly specify watchFolders
watchFolders: undefined,
},
);
const overrideConfig = getOverrideConfig(ctx, config);
return mergeConfig(config, overrideConfig);
}