Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/example/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import '@callstack/react-native-release-inspector';
import { AppRegistry } from 'react-native';
import App from './src/App';
import { name as appName } from './app.json';
Expand Down
26 changes: 0 additions & 26 deletions apps/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1747,28 +1747,6 @@ PODS:
- React-utils (= 0.85.0)
- ReactNativeDependencies
- ReactNativeDependencies (0.85.0)
- ReleaseInspector (0.1.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- Yoga (0.0.0)

DEPENDENCIES:
Expand Down Expand Up @@ -1845,7 +1823,6 @@ DEPENDENCIES:
- ReactCodegen (from `build/generated/ios/ReactCodegen`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
- ReleaseInspector (from `../../../packages/react-native-release-inspector`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)

EXTERNAL SOURCES:
Expand Down Expand Up @@ -1994,8 +1971,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
ReactNativeDependencies:
:podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec"
ReleaseInspector:
:path: "../../../packages/react-native-release-inspector"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"

Expand Down Expand Up @@ -2072,7 +2047,6 @@ SPEC CHECKSUMS:
ReactCodegen: b3184a229afd01e7f8058dd81b805b843caa2bf9
ReactCommon: fe2a3af8975e63efa60f95fca8c34dc85deee360
ReactNativeDependencies: e791424e30706256b549eaf97aaca169ca170c2b
ReleaseInspector: 6c973255d4a780a39592b9004e027090f5c85493
Yoga: e83c3121d079541e69f3c5c623faaaf933fb5812

PODFILE CHECKSUM: 4a21655142e46a595eeb8a1e91de752c15ab3838
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
Expand Down
15 changes: 10 additions & 5 deletions apps/example/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
const path = require('path');
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const { getDefaultConfig } = require('@react-native/metro-config');
const { withMetroConfig } = require('react-native-monorepo-config');
const {
withReactNativeReleaseInspector,
} = require('@callstack/react-native-release-inspector/metro');

const root = path.resolve(__dirname, '../..');

Expand All @@ -9,8 +13,9 @@ const root = path.resolve(__dirname, '../..');
*
* @type {import('metro-config').MetroConfig}
*/
const defaultConfig = getDefaultConfig(__dirname);

module.exports = mergeConfig(defaultConfig, {
watchFolders: [...(defaultConfig.watchFolders || []), root],
const config = withMetroConfig(getDefaultConfig(__dirname), {
root,
dirname: __dirname,
});

module.exports = withReactNativeReleaseInspector(config, true);
4 changes: 2 additions & 2 deletions apps/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"android": "react-native run-android --mode Release",
"ios": "react-native run-ios --mode Release",
"start": "react-native start",
"build:android": "react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"",
"build:ios": "react-native build-ios --mode Debug"
Expand Down
13 changes: 0 additions & 13 deletions apps/example/react-native.config.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
const path = require('path');

module.exports = {
project: {
ios: {
automaticPodsInstallation: true,
},
},
dependencies: {
'@callstack/react-native-release-inspector': {
root: path.join(__dirname, '../../packages/react-native-release-inspector'),
platforms: {
// Codegen script incorrectly fails without this
// So we explicitly specify the platforms with empty object
ios: {},
android: {},
},
},
},
};
5 changes: 1 addition & 4 deletions apps/example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { Text, View, StyleSheet } from 'react-native';
import { multiply } from '@callstack/react-native-release-inspector';

const result = multiply(3, 7);

export default function App() {
return (
<View style={styles.container}>
<Text>Result: {result}</Text>
<Text>Result: 3</Text>
</View>
);
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"example": "yarn workspace react-native-release-inspector-example",
"clean": "yarn workspace @callstack/react-native-release-inspector clean",
"prepare": "yarn workspace @callstack/react-native-release-inspector prepare",
"typecheck": "yarn workspace @callstack/react-native-release-inspector typecheck",
"lint": "yarn workspace @callstack/react-native-release-inspector lint",
"typecheck": "yarn workspace @callstack/react-native-release-inspector-cli typecheck && yarn workspace @callstack/react-native-release-inspector typecheck",
"lint": "yarn workspace @callstack/react-native-release-inspector-cli lint && yarn workspace @callstack/react-native-release-inspector lint",
"test": "yarn workspace @callstack/react-native-release-inspector test",
"build:android": "yarn turbo run build:android",
"build:ios": "yarn turbo run build:ios"
Expand Down
23 changes: 23 additions & 0 deletions packages/cli/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import js from '@eslint/js';
import eslintConfigPrettier from 'eslint-config-prettier';
import prettier from 'eslint-plugin-prettier';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';

export default defineConfig([
{
files: ['**/*.{js,mjs,ts}'],
extends: [
js.configs.recommended,
...tseslint.configs.recommended,
eslintConfigPrettier,
],
plugins: { prettier },
rules: {
'prettier/prettier': 'error',
},
},
{
ignores: ['node_modules/', 'lib/'],
},
]);
71 changes: 71 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"name": "@callstack/react-native-release-inspector-cli",
"version": "0.1.0",
"description": "CLI for React Native Release Inspector",
"type": "module",
"exports": {
".": {
"source": "./src/index.ts",
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"files": [
"src",
"lib",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__",
"!**/.*"
],
"bin": {
"inspector": "./lib/cli.js"
},
"scripts": {
"clean": "del-cli lib",
"build": "yarn clean && tsc -p tsconfig.build.json && node -e \"import { chmodSync } from 'node:fs'; chmodSync('lib/cli.js', 0o755);\"",
"prepare": "yarn build",
"typecheck": "tsc -p tsconfig.json",
"lint": "eslint \"**/*.{js,mjs,ts}\""
},
"keywords": [
"react-native",
"release-inspector",
"cli"
],
"repository": {
"type": "git",
"url": "git+https://github.com/callstackincubator/react-native-release-inspector.git"
},
"author": "Callstack",
"license": "MIT",
"bugs": {
"url": "https://github.com/callstackincubator/react-native-release-inspector/issues"
},
"homepage": "https://github.com/callstackincubator/react-native-release-inspector#readme",
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"prettier": {
"quoteProps": "consistent",
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": false
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@types/node": "*",
"del-cli": "^7.0.0",
"eslint": "^9.39.4",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.5",
"prettier": "^3.8.1",
"typescript": "^6.0.2",
"typescript-eslint": "^8.59.3"
},
"dependencies": {
"commander": "^14.0.3"
}
}
14 changes: 14 additions & 0 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env node

import { runCLI } from './index.js';

void runCLI().then(
(exitCode) => {
process.exitCode = exitCode;
},
(error: unknown) => {
const message = error instanceof Error ? error.message : String(error);
console.error(message);
process.exitCode = 1;
}
);
111 changes: 111 additions & 0 deletions packages/cli/src/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { spawn } from 'node:child_process';
import { readFile } from 'node:fs/promises';
import { createRequire } from 'node:module';
import { join } from 'node:path';
import { error, info } from './logging.js';

const NPX_COMMAND = process.platform === 'win32' ? 'npx.cmd' : 'npx';

type PackageJsonWithDependencies = {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
};

async function resolveReactDevToolsVersion(): Promise<string> {
const projectRequire = createRequire(join(process.cwd(), 'package.json'));

let reactNativePackageJsonPath: string;

try {
reactNativePackageJsonPath = projectRequire.resolve(
'react-native/package.json'
);
} catch {
throw new Error(
'Could not find `react-native/package.json` from the current working directory. Run `inspector start` from a React Native project with `react-native` installed.'
);
}

const reactNativePackageJson = JSON.parse(
await readFile(reactNativePackageJsonPath, 'utf8')
) as PackageJsonWithDependencies;

const reactDevToolsVersion =
reactNativePackageJson.dependencies?.['react-devtools-core'] ??
reactNativePackageJson.peerDependencies?.['react-devtools-core'] ??
reactNativePackageJson.devDependencies?.['react-devtools-core'];

if (reactDevToolsVersion == null || reactDevToolsVersion.length === 0) {
throw new Error(
'The installed `react-native` package does not declare `react-devtools-core`, so the matching React DevTools version could not be determined.'
);
}

return reactDevToolsVersion;
}

async function runCommand(command: string, args: string[]): Promise<void> {
await new Promise<void>((resolve, reject) => {
const child = spawn(command, args, {
cwd: process.cwd(),
env: process.env,
stdio: 'inherit',
});

child.once('error', (error) => {
reject(error);
});

child.once('exit', (exitCode) => {
if (exitCode === 0) {
resolve();
return;
}

reject(
new Error(
`\`${command} ${args.join(' ')}\` exited with code ${String(exitCode)}.`
)
);
});
});
}

async function setupAndroidPortReverse(): Promise<void> {
try {
await runCommand('adb', ['reverse', 'tcp:8097', 'tcp:8097']);
info('Configured Android reverse tcp:8097 -> tcp:8097.', 'dim');
} catch {
error(
'Skipping Android port reverse (adb unavailable or no Android device/emulator connected).',
'dim'
);
}
}

export async function startInspector(): Promise<void> {
info('Starting React Native Release Inspector...');
let reactDevToolsVersion: string;

try {
reactDevToolsVersion = await resolveReactDevToolsVersion();
} catch (err) {
error('Failed to resolve React DevTools version');
throw err;
}

info(
`Using react-devtools-core version ${reactDevToolsVersion} from react-native.`,
'dim'
);

await setupAndroidPortReverse();

info('Started React Native Release Inspector...', 'greenBright');

await runCommand(NPX_COMMAND, [
'--yes',
`react-devtools@${reactDevToolsVersion}`,
]);
}
Loading
Loading