From 0c95cd3f6aac816f9e7769f461f18cd74fa72ef7 Mon Sep 17 00:00:00 2001 From: Rob Hogan Date: Wed, 21 Jan 2026 10:18:07 -0800 Subject: [PATCH] Replace deprecated url.parse in dev-middleware (#55235) Summary: Use of Node's `url.parse` is deprecated and emits a runtime warning (when used in 1P code) from Node 24. This wouldn't directly affect RN users, but does create noise running from monorepo source. Changelog: [Internal] Reviewed By: GijsWeterings Differential Revision: D90992431 --- .../src/__tests__/ServerUtils.js | 3 +- .../src/inspector-proxy/InspectorProxy.js | 33 +++++++++++-------- .../src/middleware/openDebuggerMiddleware.js | 5 ++- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/dev-middleware/src/__tests__/ServerUtils.js b/packages/dev-middleware/src/__tests__/ServerUtils.js index 8c9c190158fc9b..f6f60681daf821 100644 --- a/packages/dev-middleware/src/__tests__/ServerUtils.js +++ b/packages/dev-middleware/src/__tests__/ServerUtils.js @@ -16,7 +16,6 @@ import connect from 'connect'; import http from 'http'; import https from 'https'; import * as selfsigned from 'selfsigned'; -import url from 'url'; type CreateDevMiddlewareOptions = Parameters[0]; type CreateServerOptions = { @@ -109,7 +108,7 @@ export async function createServer(options: CreateServerOptions): Promise<{ }); app.use(middleware); httpServer.on('upgrade', (request, socket, head) => { - const {pathname} = url.parse(request.url); + const {pathname} = new URL(request.url, 'http://example.com'); if (pathname != null && websocketEndpoints[pathname]) { websocketEndpoints[pathname].handleUpgrade( request, diff --git a/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js b/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js index ea887884d31966..4ac33f1b331cd5 100644 --- a/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js +++ b/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js @@ -27,7 +27,6 @@ import Device from './Device'; import EventLoopPerfTracker from './EventLoopPerfTracker'; import InspectorProxyHeartbeat from './InspectorProxyHeartbeat'; import nullthrows from 'nullthrows'; -import url from 'url'; import WS from 'ws'; const debug = require('debug')('Metro:InspectorProxy'); @@ -205,7 +204,7 @@ export default class InspectorProxy implements InspectorProxyQueries { response: ServerResponse, next: (?Error) => unknown, ) { - const pathname = url.parse(request.url).pathname; + const pathname = new URL(request.url, 'http://example.com').pathname; if ( pathname === PAGES_LIST_JSON_URL || pathname === PAGES_LIST_JSON_URL_2 @@ -336,12 +335,11 @@ export default class InspectorProxy implements InspectorProxyQueries { const wssTimestamp = Date.now(); const fallbackDeviceId = String(this.#deviceCounter++); - - const query = url.parse(req.url || '', true).query || {}; - const deviceId = query.device || fallbackDeviceId; - const deviceName = query.name || 'Unknown'; - const appName = query.app || 'Unknown'; - const isProfilingBuild = query.profiling === 'true'; + const query = tryParseQueryParams(req.url); + const deviceId = query?.get('device') || fallbackDeviceId; + const deviceName = query?.get('name') || 'Unknown'; + const appName = query?.get('app') || 'Unknown'; + const isProfilingBuild = query?.get('profiling') === 'true'; try { const deviceRelativeBaseUrl = @@ -504,9 +502,9 @@ export default class InspectorProxy implements InspectorProxyQueries { wss.on('connection', async (socket: WS, req) => { const wssTimestamp = Date.now(); - const query = url.parse(req.url || '', true).query || {}; - const deviceId = query.device; - const pageId = query.page; + const query = tryParseQueryParams(req.url); + const deviceId = query?.get('device') || null; + const pageId = query?.get('page') || null; const debuggerRelativeBaseUrl = getBaseUrlFromRequest(req) ?? this.#serverBaseUrl; const device: Device | void = deviceId @@ -593,7 +591,8 @@ export default class InspectorProxy implements InspectorProxyQueries { device.handleDebuggerConnection(socket, pageId, { debuggerRelativeBaseUrl, - userAgent: req.headers['user-agent'] ?? query.userAgent ?? null, + userAgent: + req.headers['user-agent'] ?? query?.get('userAgent') ?? null, }); socket.on('close', (code: number, reason: string) => { @@ -619,7 +618,7 @@ export default class InspectorProxy implements InspectorProxyQueries { "Connection failed to be established with DevTools for app='%s' on device='%s' and device id='%s' with error:", device?.getApp() || 'unknown', device?.getName() || 'unknown', - deviceId, + deviceId || 'unknown', error, ); socket.close(INTERNAL_ERROR_CODE, error?.toString() ?? 'Unknown error'); @@ -634,3 +633,11 @@ export default class InspectorProxy implements InspectorProxyQueries { return wss; } } + +function tryParseQueryParams(urlString: string): ?URLSearchParams { + try { + return new URL(urlString, 'http://example.com').searchParams; + } catch { + return null; + } +} diff --git a/packages/dev-middleware/src/middleware/openDebuggerMiddleware.js b/packages/dev-middleware/src/middleware/openDebuggerMiddleware.js index f274449c7b28e5..6103bd59efcbec 100644 --- a/packages/dev-middleware/src/middleware/openDebuggerMiddleware.js +++ b/packages/dev-middleware/src/middleware/openDebuggerMiddleware.js @@ -22,7 +22,6 @@ import type {IncomingMessage, ServerResponse} from 'http'; import getDevToolsFrontendUrl from '../utils/getDevToolsFrontendUrl'; import {createHash} from 'crypto'; -import url from 'url'; const LEGACY_SYNTHETIC_PAGE_TITLE = 'React Native Experimental (Improved Chrome Reloads)'; @@ -74,7 +73,7 @@ export default function openDebuggerMiddleware({ req.method === 'POST' || (experiments.enableOpenDebuggerRedirect && req.method === 'GET') ) { - const parsedUrl = url.parse(req.url, true); + const {searchParams} = new URL(req.url, 'http://example.com'); const query: { /** @deprecated Will only match legacy Hermes targets */ @@ -86,7 +85,7 @@ export default function openDebuggerMiddleware({ target?: string, panel?: string, ... - } = parsedUrl.query; + } = Object.fromEntries(searchParams); const targets = inspectorProxy .getPageDescriptions({requestorRelativeBaseUrl: new URL(serverBaseUrl)})