From 1203a7b69429ba99130be5fa53d17a58cba2348e Mon Sep 17 00:00:00 2001 From: 5o1 Date: Sat, 29 Aug 2026 16:11:58 +0800 Subject: [PATCH] Fix forwarded address for integrated previews MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Live Preview runs in a Dev Container, its server can listen on remote port 3000 while VS Code forwards it to a different local port because local port 3000 is unavailable. The issue is reproduced by opening the integrated preview after that mapping is created: the preview still navigates to 127.0.0.1:3000 instead of the Forwarded Address. Resolve the HTTP URI through vscode.env.asExternalUri before opening the integrated browser, preserve any path and query parameters from the forwarded URI, and add regression coverage for the resolved address. The integrated preview now follows VS Code’s current port mapping, so remote port 3000 opens through local port 3001 or any other Forwarded Address while retaining the Live Preview browser reuse marker. Co-authored-by: Codex --- src/editorPreview/previewManager.ts | 9 +++++++- src/test/suite/preview.test.ts | 36 ++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/editorPreview/previewManager.ts b/src/editorPreview/previewManager.ts index 7d35938c..b081e0ef 100644 --- a/src/editorPreview/previewManager.ts +++ b/src/editorPreview/previewManager.ts @@ -67,7 +67,14 @@ export class PreviewManager extends Disposable { // Check if we should use the integrated browser instead if (await SettingUtil.shouldUseIntegratedBrowser()) { - const url = `http://${connection.host}:${connection.httpPort}${path}?vscode-livepreview=true`; + const externalUri = await connection.resolveExternalHTTPUri(); + const query = new URLSearchParams(externalUri.query); + query.set('vscode-livepreview', 'true'); + const url = vscode.Uri.joinPath(externalUri, path) + .with({ + query: query.toString(), + }) + .toString(true); await vscode.commands.executeCommand(INTEGRATED_BROWSER_COMMAND, { url, openToSide: true, diff --git a/src/test/suite/preview.test.ts b/src/test/suite/preview.test.ts index b2104619..f013dc2d 100644 --- a/src/test/suite/preview.test.ts +++ b/src/test/suite/preview.test.ts @@ -14,6 +14,7 @@ import { makeSetting, testWorkspaces } from './common'; import { Connection } from '../../connectionInfo/connection'; import { WebviewComm } from '../../editorPreview/webviewComm'; import { ExternalBrowserUtils } from '../../utils/externalBrowserUtils'; +import { INTEGRATED_BROWSER_COMMAND } from '../../utils/constants'; describe('PreviewManager', () => { let sandbox: sinon.SinonSandbox; @@ -76,6 +77,39 @@ describe('PreviewManager', () => { assert.ok(goToFile.getCall(3).calledWith('/page.html', true)); }); + it('uses the forwarded address in the integrated browser', async () => { + const shouldUseIntegratedBrowser = sinon + .stub(SettingUtil, 'shouldUseIntegratedBrowser') + .resolves(true); + const resolveExternalHTTPUri = sinon + .stub(connection, 'resolveExternalHTTPUri') + .resolves( + vscode.Uri.parse('https://forwarded.example.dev/base/?token=secret') + ); + const executeCommand = sinon.stub(vscode.commands, 'executeCommand'); + + try { + await previewManager.launchFileInEmbeddedPreview( + undefined, + connection, + vscode.Uri.joinPath(testWorkspaces[0].uri, '/index.html') + ); + + assert.ok(resolveExternalHTTPUri.calledOnce); + assert.ok( + executeCommand.calledOnceWith(INTEGRATED_BROWSER_COMMAND, { + url: 'https://forwarded.example.dev/base/index.html?token=secret&vscode-livepreview=true', + openToSide: true, + reuseUrlFilter: '**?vscode-livepreview=true', + }) + ); + } finally { + executeCommand.restore(); + resolveExternalHTTPUri.restore(); + shouldUseIntegratedBrowser.restore(); + } + }); + it("previews in external preview (non-debug)", async () => { const openInBrowser = sinon.stub(ExternalBrowserUtils, 'openInBrowser'); @@ -95,4 +129,4 @@ describe('PreviewManager', () => { assert.ok(executeCommand.calledOnce); assert.ok(executeCommand.getCall(0).calledWith('extension.js-debug.debugLink', `http://${connection.host}:${connection.httpPort}/index.html`)); }); -}); \ No newline at end of file +});