From ed676009e3e2914f1bbdd43d8d247c177bea5bea Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Thu, 13 Feb 2025 18:48:10 +0100 Subject: [PATCH] webpack: Sourcemap externals when replayed in the browser (#75863) This was already implemented in the middleware for Turbopack but absent when Webpack was used. We now always prefer the native `findSourceMap` over invoking Webpack's API. This way stackframes from externals are now properly sourcemapped (and therefore ignore-listed) Notice how the `react-server-dom-webpack...` stackframe (`console.error` method) wasn't ignore-listed before. Before: ![CleanShot 2025-02-10 at 14.34.44.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/dLGs20hkgfWzupsPjSxb/2a8147d4-4b6f-4170-ae36-8b544ff0bb1a.png) After: ![CleanShot 2025-02-10 at 14.36.15.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/dLGs20hkgfWzupsPjSxb/f713e36d-88f4-4185-8bf8-0293a7b7f4f1.png) --- .../server/middleware-webpack.ts | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/next/src/client/components/react-dev-overlay/server/middleware-webpack.ts b/packages/next/src/client/components/react-dev-overlay/server/middleware-webpack.ts index a56fe4320ca21..08639644a64f4 100644 --- a/packages/next/src/client/components/react-dev-overlay/server/middleware-webpack.ts +++ b/packages/next/src/client/components/react-dev-overlay/server/middleware-webpack.ts @@ -1,4 +1,5 @@ import { constants as FS, promises as fs } from 'fs' +import { findSourceMap, type SourceMap } from 'module' import path from 'path' import { fileURLToPath, pathToFileURL } from 'url' import { @@ -128,8 +129,10 @@ async function findOriginalSourcePositionAndContent( } } -export function getIgnoredSources(sourceMap: RawSourceMap): IgnoredSources { - const ignoreList = new Set() +export function getIgnoredSources( + sourceMap: RawSourceMap & { ignoreList?: number[] } +): IgnoredSources { + const ignoreList = new Set(sourceMap.ignoreList ?? []) const moduleFilenames = sourceMap?.sources ?? [] for (let index = 0; index < moduleFilenames.length; index++) { @@ -289,6 +292,26 @@ async function getSource( ): Promise { const { getCompilations } = options + let nativeSourceMap: SourceMap | undefined + try { + nativeSourceMap = findSourceMap(sourceURL) + } catch (cause) { + throw new Error( + `${sourceURL}: Invalid source map. Only conformant source maps can be used to find the original code.`, + { cause } + ) + } + + if (nativeSourceMap !== undefined) { + const sourceMapPayload = nativeSourceMap.payload + return { + type: 'file', + sourceMap: sourceMapPayload, + ignoredSources: getIgnoredSources(sourceMapPayload), + moduleURL: sourceURL, + } + } + if (path.isAbsolute(sourceURL)) { sourceURL = pathToFileURL(sourceURL).href } @@ -316,7 +339,7 @@ async function getSource( .replace(/\?\d+$/, '') // (rsc)/./src/hello.tsx => ./src/hello.tsx - const modulePath = moduleId.replace(/^(\(.*\)\/?)/, '') + const moduleURL = moduleId.replace(/^(\(.*\)\/?)/, '') for (const compilation of getCompilations()) { const sourceMap = await getSourceMapFromCompilation(moduleId, compilation) @@ -328,7 +351,7 @@ async function getSource( sourceMap, compilation, moduleId, - moduleURL: modulePath, + moduleURL, ignoredSources, } }