diff --git a/packages/react-devtools-shared/src/__tests__/utils-test.js b/packages/react-devtools-shared/src/__tests__/utils-test.js index dcffd2a228b..9b9e82102cc 100644 --- a/packages/react-devtools-shared/src/__tests__/utils-test.js +++ b/packages/react-devtools-shared/src/__tests__/utils-test.js @@ -421,6 +421,26 @@ function f() { } await expect(run('http://test/c.mjs')).resolves.toStrictEqual(result); await expect(run('http://test/d.mjs')).resolves.toStrictEqual(result); }); + + it('should not throw for invalid base URL with relative source map', async () => { + const fs2 = { + 'bundle.js': `${source}bundle.js.map`, + }; + const fetch2 = async url => fs2[url] || null; + const run = url => symbolicateSource(fetch2, url, 1, 1); + await expect(run('bundle.js')).resolves.toBe(null); + }); + + it('should resolve absolute source map even if base URL is invalid', async () => { + const fs3 = { + 'invalid-base.js': `${source}http://test/a.mjs.map`, + 'http://test/a.mts': `export function f() {}`, + 'http://test/a.mjs.map': `{"version":3,"file":"a.mjs","sourceRoot":"","sources":["a.mts"],"names":[],"mappings":";;AAAA,cAAsB;AAAtB,SAAgB,CAAC,KAAI,CAAC"}`, + }; + const fetch3 = async url => fs3[url] || null; + const run = url => symbolicateSource(fetch3, url, 4, 10); + await expect(run('invalid-base.js')).resolves.toStrictEqual(result); + }); }); describe('formatConsoleArguments', () => { diff --git a/packages/react-devtools-shared/src/symbolicateSource.js b/packages/react-devtools-shared/src/symbolicateSource.js index 267e291e120..092b1f8187a 100644 --- a/packages/react-devtools-shared/src/symbolicateSource.js +++ b/packages/react-devtools-shared/src/symbolicateSource.js @@ -75,7 +75,18 @@ export async function symbolicateSource( resourceLine.length, ); - const sourceMapURL = new URL(sourceMapAt, sourceURL).toString(); + // Compute the absolute source map URL. If the base URL is invalid, gracefully bail. + let sourceMapURL; + try { + sourceMapURL = new URL(sourceMapAt, sourceURL).toString(); + } catch (e) { + // Fallback: try if sourceMapAt is already an absolute URL; otherwise give up. + try { + sourceMapURL = new URL(sourceMapAt).toString(); + } catch (_e) { + return null; + } + } const sourceMap = await fetchFileWithCaching(sourceMapURL).catch( () => null, );