1import resolveFrom from 'resolve-from'; 2 3// These resolvers enable us to test the CLI in older projects. 4// We may be able to get rid of this in the future. 5// TODO: Maybe combine with AsyncResolver? 6class MetroImportError extends Error { 7 constructor(projectRoot: string, moduleId: string) { 8 super( 9 `Missing package "${moduleId}" in the project at: ${projectRoot}\n` + 10 'This usually means "react-native" is not installed. ' + 11 'Please verify that dependencies in package.json include "react-native" ' + 12 'and run `yarn` or `npm install`.' 13 ); 14 } 15} 16 17function resolveFromProject(projectRoot: string, moduleId: string) { 18 const resolvedPath = resolveFrom.silent(projectRoot, moduleId); 19 if (!resolvedPath) { 20 throw new MetroImportError(projectRoot, moduleId); 21 } 22 return resolvedPath; 23} 24 25function importFromProject(projectRoot: string, moduleId: string) { 26 return require(resolveFromProject(projectRoot, moduleId)); 27} 28 29/** Import `metro` from the project. */ 30export function importMetroFromProject(projectRoot: string): typeof import('metro') { 31 return importFromProject(projectRoot, 'metro'); 32} 33export function importMetroCreateWebsocketServerFromProject( 34 projectRoot: string 35): typeof import('metro/src/lib/createWebsocketServer').createWebsocketServer { 36 return importFromProject(projectRoot, 'metro/src/lib/createWebsocketServer'); 37} 38export function importMetroHmrServerFromProject( 39 projectRoot: string 40): typeof import('metro/src/HmrServer').MetroHmrServer { 41 return importFromProject(projectRoot, 'metro/src/HmrServer'); 42} 43 44/** Import `@expo/metro-config` from the project. */ 45export function importExpoMetroConfigFromProject( 46 projectRoot: string 47): typeof import('@expo/metro-config') { 48 return importFromProject(projectRoot, '@expo/metro-config'); 49} 50 51/** Import `metro-resolver` from the project. */ 52export function importMetroResolverFromProject( 53 projectRoot: string 54): typeof import('metro-resolver') { 55 return importFromProject(projectRoot, 'metro-resolver'); 56} 57 58/** Import `metro-inspector-proxy` from the project. */ 59export function importMetroInspectorProxyFromProject( 60 projectRoot: string 61): typeof import('metro-inspector-proxy') { 62 return importFromProject(projectRoot, 'metro-inspector-proxy'); 63} 64 65/** Import `metro-inspector-proxy/src/Device` from the project. */ 66export function importMetroInspectorDeviceFromProject( 67 projectRoot: string 68): typeof import('metro-inspector-proxy/src/Device') { 69 return importFromProject(projectRoot, 'metro-inspector-proxy/src/Device'); 70} 71 72/** 73 * Import the internal `saveAssets()` function from `react-native` for the purpose 74 * of saving production assets as-is instead of converting them to a hash. 75 */ 76export function importCliSaveAssetsFromProject( 77 projectRoot: string 78): typeof import('@react-native-community/cli-plugin-metro/build/commands/bundle/saveAssets').default { 79 return importFromProject( 80 projectRoot, 81 '@react-native-community/cli-plugin-metro/build/commands/bundle/saveAssets' 82 ).default; 83} 84 85export function importCliBuildBundleWithConfigFromProject( 86 projectRoot: string 87): typeof import('@react-native-community/cli-plugin-metro/build/commands/bundle/buildBundle').buildBundleWithConfig { 88 return importFromProject( 89 projectRoot, 90 '@react-native-community/cli-plugin-metro/build/commands/bundle/buildBundle' 91 ).buildBundleWithConfig; 92} 93 94/** Resolve the installed Metro version from project */ 95export function resolveMetroVersionFromProject(projectRoot: string): string { 96 return importFromProject(projectRoot, 'metro/package.json').version; 97} 98