import path from "path" ; import type { Config as CLIConfig } from "@react-native-community/cli-types" ; import type { Reporter } from "metro" ; import { loadConfig , ConfigT , InputConfigT } from "metro-config" ; import { resolve , Resolution } from "metro-resolver" ; const INTERNAL_CALLSITES_REGEX = new RegExp ( [ "/Libraries/Renderer/implementations/.+\\.js$" , "/Libraries/BatchedBridge/MessageQueue\\.js$" , "/Libraries/YellowBox/.+\\.js$" , "/Libraries/LogBox/.+\\.js$" , "/Libraries/Core/Timers/.+\\.js$" , "/node_modules/react-devtools-core/.+\\.js$" , "/node_modules/react-refresh/.+\\.js$" , "/node_modules/scheduler/.+\\.js$" , ] . join ( "|" ) ) ; function reactNativePlatformResolver ( platformImplementations ) { return ( context , _realModuleName , platform , moduleName ) : Resolution => { const backupResolveRequest = context . resolveRequest ; delete context . resolveRequest ; try { let modifiedModuleName = moduleName ; if ( platformImplementations [ platform ] ) { if ( moduleName === "react-native" ) { modifiedModuleName = platformImplementations [ platform ] ; } else if ( moduleName . startsWith ( "react-native/" ) ) { modifiedModuleName = `${ platformImplementations [ platform ] }/${ modifiedModuleName . slice ( "react-native/" . length ) }` ; } } const result = resolve ( context , modifiedModuleName , platform ) ; return result ; } finally { context . resolveRequest = backupResolveRequest ; } } ; } function getAsyncRequireModulePath ( ) { try { return require . resolve ( "metro-runtime/src/modules/asyncRequire" ) ; } catch ( _ ) { return require . resolve ( "metro/src/lib/bundle-modules/asyncRequire" ) ; } } function getDefaultConfig ( cliConfig ) { const outOfTreePlatforms = Object . keys ( cliConfig . platforms ) . filter ( ( platform ) => cliConfig . platforms [ platform ] . npmPackageName ) ; const defaultConfig = { resolver : { resolveRequest : outOfTreePlatforms . length === 0 ? undefined : reactNativePlatformResolver ( outOfTreePlatforms . reduce < { [ platform ] : string ; } > ( ( result , platform ) => { result [ platform ] = cliConfig . platforms [ platform ] . npmPackageName ! ; return result ; } , { } ) ) , resolverMainFields : [ "react-native" , "browser" , "main" ] , platforms : [ ... Object . keys ( cliConfig . platforms ) , "native" ] } , serializer : { getModulesRunBeforeMainModule : ( ) => [ require . resolve ( path . join ( cliConfig . reactNativePath , "Libraries/Core/InitializeCore" ) ) , ... outOfTreePlatforms . map ( ( platform ) => require . resolve ( `${ cliConfig . platforms [ platform ] . npmPackageName ! }/Libraries/Core/InitializeCore` ) ) , ] , getPolyfills : ( ) => require ( path . join ( cliConfig . reactNativePath , "rn-get-polyfills" ) ) ( ) } , server : { port : Number ( process . env . RCT_METRO_PORT ) || 8081 } , symbolicator : { customizeFrame : ( frame ) => { const collapse = Boolean ( frame . file && INTERNAL_CALLSITES_REGEX . test ( frame . file ) ) ; return { collapse } ; } } , transformer : { allowOptionalDependencies : true , babelTransformerPath : require . resolve ( "metro-react-native-babel-transformer" ) , assetRegistryPath : "react-native/Libraries/Image/AssetRegistry" , asyncRequireModulePath : getAsyncRequireModulePath ( ) } , watchFolders : [ ] } ; return defaultConfig as InputConfigT ; } export type MetroConfigOverrides = { config ? : string ; port ? : number ; projectRoot ? : string ; watchFolders ? : string [ ] ; sourceExts ? : string [ ] ; maxWorkers ? : number ; resetCache ? : boolean ; reporter ? : Reporter ; assetPlugins ? : string [ ] ; } ; param cliConfig react-native-community param overrides returns export function loadMetroConfig ( cliConfig , overrides ) { const defaultConfig = getDefaultConfig ( cliConfig ) ; if ( overrides . reporter ) { defaultConfig . reporter = overrides . reporter ; } if ( overrides . assetPlugins ) { defaultConfig . transformer . assetPlugins = assetPlugins ; } return loadConfig ( { cwd : cliConfig . root , ... overrides } , defaultConfig ) ; }