From c5a63d700e0bcf0a87447daf198e032566f3d479 Mon Sep 17 00:00:00 2001 From: apple <245524539+apples-kksk@users.noreply.github.com> Date: Sat, 16 May 2026 16:07:17 +0800 Subject: [PATCH] Fix DevTools links for Node module stack frames --- patch/patches/devtools.patch | 52 +++++++++++++++++ src/nwjs_browsertest.cc | 58 +++++++++++++++++++ .../issue4269-node-module-link/index.html | 15 +++++ .../issue4269-node-module-link/myModule.js | 3 + .../issue4269-node-module-link/myModule2.js | 1 + .../issue4269-node-module-link/package.json | 4 ++ 6 files changed, 133 insertions(+) create mode 100644 test/browser/issue4269-node-module-link/index.html create mode 100644 test/browser/issue4269-node-module-link/myModule.js create mode 100644 test/browser/issue4269-node-module-link/myModule2.js create mode 100644 test/browser/issue4269-node-module-link/package.json diff --git a/patch/patches/devtools.patch b/patch/patches/devtools.patch index cc56e64a7f..2724db7302 100644 --- a/patch/patches/devtools.patch +++ b/patch/patches/devtools.patch @@ -32,3 +32,55 @@ index 0a5ec620b1..8a34390ac5 100644 let parsedURL; // This is only to work around invalid URLs we're occasionally getting from some tests. // TODO(caseq): make sure tests supply valid URLs or we specifically handle invalid ones. +diff --git a/front_end/ui/helpers/OpenInNewTab.ts b/front_end/ui/helpers/OpenInNewTab.ts +index cfa93f3..7f2cda0 100644 +--- front_end/ui/helpers/OpenInNewTab.ts ++++ front_end/ui/helpers/OpenInNewTab.ts +@@ -57,8 +57,46 @@ import * as SDK from '../../core/sdk/sdk.js'; + * @throws TypeError if `url` is not a valid URL. + * @see https://en.wikipedia.org/wiki/UTM_parameters + */ ++function encodeFilePath(path: string): string { ++ const parts = path.split('/'); ++ return parts.map((part, index) => { ++ if (index === 0 && /^[A-Za-z]:$/.test(part)) { ++ return part; ++ } ++ return encodeURIComponent(part); ++ }).join('/'); ++} ++ ++function fileURLFromAbsolutePath(path: string): URL|null { ++ if (path.startsWith('/')) { ++ return new URL(`file://${encodeFilePath(path)}`); ++ } ++ if (/^[A-Za-z]:[\\/]/.test(path)) { ++ const normalizedPath = path.replace(/\\/g, '/'); ++ return new URL(`file:///${encodeFilePath(normalizedPath)}`); ++ } ++ return null; ++} ++ ++function normalizeURLToOpen(url: URL|string): URL { ++ if (url instanceof URL) { ++ return url; ++ } ++ try { ++ return new URL(url); ++ } catch (error) { ++ // NW.js can surface Node stack frames as raw absolute paths. Keep stack ++ // filenames unchanged, but open those links as file URLs. ++ const fileURL = fileURLFromAbsolutePath(url); ++ if (fileURL) { ++ return fileURL; ++ } ++ throw error; ++ } ++} ++ + export function openInNewTab(url: URL|string): void { +- url = new URL(url); ++ url = normalizeURLToOpen(url); + if (Common.ParsedURL.schemeIs(url, 'javascript:')) { + return; + } diff --git a/src/nwjs_browsertest.cc b/src/nwjs_browsertest.cc index c3844ab6db..fe8be5b664 100644 --- a/src/nwjs_browsertest.cc +++ b/src/nwjs_browsertest.cc @@ -1144,6 +1144,64 @@ IN_PROC_BROWSER_TEST_F(NWJSDevToolsTest, Issue4269Crash) { EXPECT_TRUE(base::EndsWith(url, "inspect.html")); } +IN_PROC_BROWSER_TEST_F(NWJSDevToolsTest, Issue4269NodeModuleLink) { + LoadAndLaunchApp("issue4269-node-module-link", "Launched"); + content::WebContents* wc = GetAppWebContents("index.html"); + ASSERT_TRUE(wc); + + DevToolsWindowCreationObserver observer; + ASSERT_TRUE(EvalJs(wc, "nw.Window.get().showDevTools()").is_ok()); + observer.WaitForLoad(); + DevToolsWindow* window = observer.devtools_window(); + SwitchToPanel(window, "console"); + WebContents* devtools = DevToolsWindowTesting::Get(window)->main_web_contents(); + + ui_test_utils::BrowserCreatedObserver new_browser_observer; + ASSERT_TRUE(EvalJs(devtools, R"js( + (() => new Promise((resolve, reject) => { + const clickLink = () => { + const links = Array.from(document.querySelectorAll( + '.console-message-text .devtools-link')); + const link = + links.find(link => link.textContent.includes('myModule2.js')); + if (!link) { + return false; + } + link.click(); + resolve(true); + return true; + }; + if (clickLink()) { + return; + } + const observer = new MutationObserver(() => { + if (clickLink()) { + observer.disconnect(); + } + }); + observer.observe(document.body, { + childList: true, + subtree: true, + characterData: true + }); + setTimeout(() => { + observer.disconnect(); + reject(new Error('missing myModule2.js console link')); + }, 5000); + }))() + )js").is_ok()); + Browser* active_browser = new_browser_observer.Wait(); + ui_test_utils::WaitUntilBrowserBecomeActive(active_browser); + content::WebContents* popup_contents = + active_browser->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(content::WaitForLoadStop(popup_contents)); + + std::string url = popup_contents->GetLastCommittedURL().spec(); + LOG(WARNING) << url; + EXPECT_TRUE(url.rfind("file://", 0) == 0); + EXPECT_TRUE(base::EndsWith(url, "myModule2.js")); +} + IN_PROC_BROWSER_TEST_F(NWAppTest, LocalFlash) { std::string contents; base::FilePath test_dir = test_data_dir_.Append(FILE_PATH_LITERAL("platform_apps")).Append(FILE_PATH_LITERAL("local_flash")); diff --git a/test/browser/issue4269-node-module-link/index.html b/test/browser/issue4269-node-module-link/index.html new file mode 100644 index 0000000000..071c8a7d20 --- /dev/null +++ b/test/browser/issue4269-node-module-link/index.html @@ -0,0 +1,15 @@ + + + + + Node module link + + + + + + diff --git a/test/browser/issue4269-node-module-link/myModule.js b/test/browser/issue4269-node-module-link/myModule.js new file mode 100644 index 0000000000..0ca1198e20 --- /dev/null +++ b/test/browser/issue4269-node-module-link/myModule.js @@ -0,0 +1,3 @@ +setTimeout(() => { + nw.require('./myModule2'); +}, 0); diff --git a/test/browser/issue4269-node-module-link/myModule2.js b/test/browser/issue4269-node-module-link/myModule2.js new file mode 100644 index 0000000000..7339ee13fd --- /dev/null +++ b/test/browser/issue4269-node-module-link/myModule2.js @@ -0,0 +1 @@ +myTestError(); diff --git a/test/browser/issue4269-node-module-link/package.json b/test/browser/issue4269-node-module-link/package.json new file mode 100644 index 0000000000..d31cdae6d1 --- /dev/null +++ b/test/browser/issue4269-node-module-link/package.json @@ -0,0 +1,4 @@ +{ + "name": "issue4269-node-module-link", + "main": "index.html" +}