From 9b28ddf6749bc6eec1f26892062de5ce0e80b1db Mon Sep 17 00:00:00 2001 From: Vivek JM Date: Wed, 13 May 2026 01:43:42 +0530 Subject: [PATCH] fix: allow run-windows to start Metro on custom port --- ...-58f79ee3-6346-45f1-bd07-2ffac4fb32a1.json | 7 +++++++ .../commands/runWindows/runWindowsOptions.ts | 18 ++++++++++++++--- .../cli/src/e2etest/runWindows.test.ts | 10 ++++++++++ .../cli/src/utils/deploy.ts | 20 +++++++++++++------ 4 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 change/@react-native-windows-cli-58f79ee3-6346-45f1-bd07-2ffac4fb32a1.json diff --git a/change/@react-native-windows-cli-58f79ee3-6346-45f1-bd07-2ffac4fb32a1.json b/change/@react-native-windows-cli-58f79ee3-6346-45f1-bd07-2ffac4fb32a1.json new file mode 100644 index 00000000000..f949464b1a2 --- /dev/null +++ b/change/@react-native-windows-cli-58f79ee3-6346-45f1-bd07-2ffac4fb32a1.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Add a run-windows port option for Metro", + "packageName": "@react-native-windows/cli", + "email": "vivekjm77@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/@react-native-windows/cli/src/commands/runWindows/runWindowsOptions.ts b/packages/@react-native-windows/cli/src/commands/runWindows/runWindowsOptions.ts index 6b119862546..d9d0ba0f618 100644 --- a/packages/@react-native-windows/cli/src/commands/runWindows/runWindowsOptions.ts +++ b/packages/@react-native-windows/cli/src/commands/runWindows/runWindowsOptions.ts @@ -28,6 +28,7 @@ export type BuildConfig = 'Debug' | 'DebugBundle' | 'Release' | 'ReleaseBundle'; * deploy-from-layout: Force deploy from layout, even in release builds * sln: String - Solution file to build * msbuildprops: String - Comma separated props to pass to msbuild, eg: prop1=value1,prop2=value2 + * port: Number - Port to use for the React Native packager * direct-debugging: Number - Enable direct debugging on specified port * no-telemetry: Boolean - Disables sending telemetry that allows analysis of usage and failures of the react-native-windows CLI */ @@ -52,6 +53,7 @@ export interface RunWindowsOptions { msbuildprops?: string; buildLogDirectory?: string; info?: boolean; + port?: number; directDebugging?: number; telemetry?: boolean; } @@ -147,6 +149,12 @@ export const runWindowsOptions: CommandOption[] = [ name: '--info', description: 'Dump environment information', }, + { + name: '--port [number]', + description: 'Port to use for the React Native packager', + default: 8081, + parse: parsePort, + }, { name: '--direct-debugging [number]', description: 'Enable direct debugging on specified port', @@ -171,13 +179,17 @@ function parseBuildArch(arg: string): BuildArch { } function parseDirectDebuggingPort(arg: string): number { - const num = parseInt(arg, 10); + return parsePort(arg, '--direct-debugging'); +} + +function parsePort(arg: string, optionName = '--port'): number { + const num = Number(arg); if (!Number.isInteger(num)) { - errorOut(`Expected argument '--direct-debugging' to be a number`); + errorOut(`Expected argument '${optionName}' to be a number`); } if (num < 1024 || num >= 65535) { - errorOut('Direct debugging port it out of range'); + errorOut(`${optionName} is out of range`); } return num; diff --git a/packages/@react-native-windows/cli/src/e2etest/runWindows.test.ts b/packages/@react-native-windows/cli/src/e2etest/runWindows.test.ts index 23c1f3b0b4e..88d38ddb915 100644 --- a/packages/@react-native-windows/cli/src/e2etest/runWindows.test.ts +++ b/packages/@react-native-windows/cli/src/e2etest/runWindows.test.ts @@ -38,6 +38,7 @@ function validateOptionName( case 'msbuildprops': case 'buildLogDirectory': case 'info': + case 'port': case 'directDebugging': case 'telemetry': return true; @@ -77,3 +78,12 @@ test('runWindowsOptions - validate options', () => { ).toBe(true); } }); + +test('runWindowsOptions - parses packager port', () => { + const portOption = runWindowsOptions.find(option => + option.name.startsWith('--port'), + ); + + expect(portOption).toBeDefined(); + expect(portOption!.parse!('9000')).toBe(9000); +}); diff --git a/packages/@react-native-windows/cli/src/utils/deploy.ts b/packages/@react-native-windows/cli/src/utils/deploy.ts index 4335d166c36..b3e0e28002c 100644 --- a/packages/@react-native-windows/cli/src/utils/deploy.ts +++ b/packages/@react-native-windows/cli/src/utils/deploy.ts @@ -45,8 +45,8 @@ export function getBuildConfiguration(options: RunWindowsOptions): BuildConfig { ? 'ReleaseBundle' : 'Release' : options.bundle - ? 'DebugBundle' - : 'Debug'; + ? 'DebugBundle' + : 'Debug'; } function shouldDeployByPackage( @@ -314,8 +314,8 @@ export async function deployToDevice( const deployTarget = options.target ? options.target : options.emulator - ? 'emulator' - : 'device'; + ? 'emulator' + : 'device'; const deployTool = new WinAppDeployTool(); const appxManifest = getAppxManifest(options, projectName); const shouldLaunch = shouldLaunchApp(options); @@ -512,9 +512,11 @@ export function startServerInNewWindow( options: RunWindowsOptions, verbose: boolean, ): Promise { + const port = options.port ?? 8081; + return new Promise(resolve => { http - .get('http://localhost:8081/status', res => { + .get(`http://localhost:${port}/status`, res => { if (res.statusCode === 200) { newSuccess('React-Native Server already started'); } else { @@ -537,5 +539,11 @@ function launchServer(options: RunWindowsOptions, verbose: boolean) { stdio: verbose ? 'inherit' : 'ignore', }; - spawn('cmd.exe', ['/C', 'start npx @react-native-community/cli start'], opts); + const port = options.port ?? 8081; + + spawn( + 'cmd.exe', + ['/C', `start npx @react-native-community/cli start --port ${port}`], + opts, + ); }