From a54b788e80555b95b5c64b9e425203742d14bc6a Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Thu, 17 Apr 2025 18:21:05 +0200 Subject: [PATCH 1/3] [devtools] Fix "View source" for sources with URLs that aren't normalized --- packages/react-devtools-extensions/src/main/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-extensions/src/main/index.js b/packages/react-devtools-extensions/src/main/index.js index 7d94449fcc748..5a5624ecb0632 100644 --- a/packages/react-devtools-extensions/src/main/index.js +++ b/packages/react-devtools-extensions/src/main/index.js @@ -128,7 +128,13 @@ function createBridgeAndStore() { : source; // We use 1-based line and column, Chrome expects them 0-based. - chrome.devtools.panels.openResource(sourceURL, line - 1, column - 1); + chrome.devtools.panels.openResource( + // openResource needs normalized URLs. + // Using `URL` triggers path normalization. + new URL(sourceURL).toString(), + line - 1, + column - 1, + ); }; // TODO (Webpack 5) Hopefully we can remove this prop after the Webpack 5 migration. From 7b5657b0e8ed20e349a4809d570e0b8018591200 Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Thu, 17 Apr 2025 18:45:02 +0200 Subject: [PATCH 2/3] Move all URL normalization to platform specific code --- .../src/main/fetchFileWithCaching.js | 3 +-- packages/react-devtools-shared/src/symbolicateSource.js | 4 +--- packages/react-devtools-shared/src/utils.js | 5 ----- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/react-devtools-extensions/src/main/fetchFileWithCaching.js b/packages/react-devtools-extensions/src/main/fetchFileWithCaching.js index 67725e27d8a7f..3b35f0f75cf2e 100644 --- a/packages/react-devtools-extensions/src/main/fetchFileWithCaching.js +++ b/packages/react-devtools-extensions/src/main/fetchFileWithCaching.js @@ -1,6 +1,5 @@ /* global chrome */ -import {normalizeUrl} from 'react-devtools-shared/src/utils'; import {__DEBUG__} from 'react-devtools-shared/src/constants'; let debugIDCounter = 0; @@ -117,7 +116,7 @@ async function fetchFileWithCaching(url: string): Promise { chrome.devtools.inspectedWindow.getResources(r => resolve(r)), ); - const normalizedReferenceURL = normalizeUrl(url); + const normalizedReferenceURL = new URL(url).toString(); const resource = resources.find(r => r.url === normalizedReferenceURL); if (resource != null) { diff --git a/packages/react-devtools-shared/src/symbolicateSource.js b/packages/react-devtools-shared/src/symbolicateSource.js index 9430e88b3fc15..6504ab2594091 100644 --- a/packages/react-devtools-shared/src/symbolicateSource.js +++ b/packages/react-devtools-shared/src/symbolicateSource.js @@ -7,7 +7,6 @@ * @flow */ -import {normalizeUrl} from 'react-devtools-shared/src/utils'; import SourceMapConsumer from 'react-devtools-shared/src/hooks/SourceMapConsumer'; import type {Source} from 'react-devtools-shared/src/shared/types'; @@ -91,9 +90,8 @@ export async function symbolicateSource( try { // sourceMapURL = https://react.dev/script.js.map void new URL(possiblyURL); // test if it is a valid URL - const normalizedURL = normalizeUrl(possiblyURL); - return {sourceURL: normalizedURL, line, column}; + return {sourceURL: possiblyURL, line, column}; } catch (e) { // This is not valid URL if ( diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index 12c9fb739ce95..1ccdef50e9501 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -996,11 +996,6 @@ export function backendToFrontendSerializedElementMapper( }; } -// Chrome normalizes urls like webpack-internals:// but new URL don't, so cannot use new URL here. -export function normalizeUrl(url: string): string { - return url.replace('/./', '/'); -} - export function getIsReloadAndProfileSupported(): boolean { // Notify the frontend if the backend supports the Storage API (e.g. localStorage). // If not, features like reload-and-profile will not work correctly and must be disabled. From d7ad0d208ad3aa15854e67bd5e54f21866ecf527 Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Thu, 17 Apr 2025 19:22:42 +0200 Subject: [PATCH 3/3] Handle invalid URLs --- .../src/main/fetchFileWithCaching.js | 3 ++- .../react-devtools-extensions/src/main/index.js | 5 ++--- packages/react-devtools-shared/src/utils.js | 13 +++++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/react-devtools-extensions/src/main/fetchFileWithCaching.js b/packages/react-devtools-extensions/src/main/fetchFileWithCaching.js index 3b35f0f75cf2e..97bf1fe35bcbe 100644 --- a/packages/react-devtools-extensions/src/main/fetchFileWithCaching.js +++ b/packages/react-devtools-extensions/src/main/fetchFileWithCaching.js @@ -1,5 +1,6 @@ /* global chrome */ +import {normalizeUrlIfValid} from 'react-devtools-shared/src/utils'; import {__DEBUG__} from 'react-devtools-shared/src/constants'; let debugIDCounter = 0; @@ -116,7 +117,7 @@ async function fetchFileWithCaching(url: string): Promise { chrome.devtools.inspectedWindow.getResources(r => resolve(r)), ); - const normalizedReferenceURL = new URL(url).toString(); + const normalizedReferenceURL = normalizeUrlIfValid(url); const resource = resources.find(r => r.url === normalizedReferenceURL); if (resource != null) { diff --git a/packages/react-devtools-extensions/src/main/index.js b/packages/react-devtools-extensions/src/main/index.js index 5a5624ecb0632..63d25819539f1 100644 --- a/packages/react-devtools-extensions/src/main/index.js +++ b/packages/react-devtools-extensions/src/main/index.js @@ -16,6 +16,7 @@ import { LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY, } from 'react-devtools-shared/src/constants'; import {logEvent} from 'react-devtools-shared/src/Logger'; +import {normalizeUrlIfValid} from 'react-devtools-shared/src/utils'; import { setBrowserSelectionFromReact, @@ -129,9 +130,7 @@ function createBridgeAndStore() { // We use 1-based line and column, Chrome expects them 0-based. chrome.devtools.panels.openResource( - // openResource needs normalized URLs. - // Using `URL` triggers path normalization. - new URL(sourceURL).toString(), + normalizeUrlIfValid(sourceURL), line - 1, column - 1, ); diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index 1ccdef50e9501..b0a8f5c53e0cd 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -996,6 +996,19 @@ export function backendToFrontendSerializedElementMapper( }; } +/** + * Should be used when treating url as a Chrome Resource URL. + */ +export function normalizeUrlIfValid(url: string): string { + try { + // TODO: Chrome will use the basepath to create a Resource URL. + return new URL(url).toString(); + } catch { + // Giving up if it's not a valid URL without basepath + return url; + } +} + export function getIsReloadAndProfileSupported(): boolean { // Notify the frontend if the backend supports the Storage API (e.g. localStorage). // If not, features like reload-and-profile will not work correctly and must be disabled.