fix(vscode): avoid navigation reload on chunk load failure
Browser-style chunk recovery used location.reload inside VS Code webviews, where navigation reload is unsupported. Preserve import retries and let the original failure reach the error boundary instead. Validated with focused regression tests, UI type-check and lint, and the VS Code webview build. The reported gray-screen crash has not been reproduced.
This commit is contained in:
@@ -3,6 +3,41 @@ import { describe, expect, test } from 'bun:test';
|
||||
import { importWithChunkRecovery } from './chunkLoadRecovery';
|
||||
|
||||
describe('importWithChunkRecovery', () => {
|
||||
test('preserves the import error without navigating the VS Code webview', async () => {
|
||||
const previousWindow = Object.getOwnPropertyDescriptor(globalThis, 'window');
|
||||
let reloadCount = 0;
|
||||
let markerWrites = 0;
|
||||
Object.defineProperty(globalThis, 'window', {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: {
|
||||
__VSCODE_CONFIG__: { workspaceFolder: 'C:/repo', workspaceFolders: [] },
|
||||
sessionStorage: {
|
||||
getItem: () => null,
|
||||
setItem: () => { markerWrites += 1; },
|
||||
},
|
||||
setTimeout: (callback: () => void) => { callback(); return 0; },
|
||||
location: { reload: () => { reloadCount += 1; } },
|
||||
},
|
||||
});
|
||||
|
||||
const failure = new Error('Failed to fetch dynamically imported module');
|
||||
let attempts = 0;
|
||||
try {
|
||||
const caught = await importWithChunkRecovery(async () => {
|
||||
attempts += 1;
|
||||
throw failure;
|
||||
}).catch((error: Error) => error);
|
||||
expect(caught).toBe(failure);
|
||||
expect(attempts).toBe(2);
|
||||
expect(reloadCount).toBe(0);
|
||||
expect(markerWrites).toBe(0);
|
||||
} finally {
|
||||
if (previousWindow) Object.defineProperty(globalThis, 'window', previousWindow);
|
||||
else Reflect.deleteProperty(globalThis, 'window');
|
||||
}
|
||||
});
|
||||
|
||||
test('schedules recovery reload when stored reload marker is corrupt', async () => {
|
||||
const globalWithWindow = globalThis as unknown as { window?: unknown };
|
||||
const previousWindow = globalWithWindow.window;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { lazy } from 'react';
|
||||
import { isVSCodeRuntime } from './desktop';
|
||||
|
||||
declare const __APP_VERSION__: string | undefined;
|
||||
|
||||
@@ -42,6 +43,9 @@ function reloadMarkerSignature(error: unknown): string {
|
||||
|
||||
function scheduleReloadOnce(error: unknown): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
// VS Code owns webview navigation. Keep the import failure available to the
|
||||
// error boundary instead of replacing the app with an unsupported reload.
|
||||
if (isVSCodeRuntime()) return;
|
||||
|
||||
const now = Date.now();
|
||||
const signature = reloadMarkerSignature(error);
|
||||
|
||||
@@ -110,6 +110,10 @@ opening a connection. Session sync still uses the OpenCode SSE bridge and
|
||||
global session polling. Sending the control stream to the webview origin caused
|
||||
repeated `403` responses and URL-token requests to `/auth/url-token`.
|
||||
|
||||
Shared lazy imports retry a failed chunk load, but skip browser-navigation
|
||||
recovery in VS Code. `window.location.reload()` is unsupported inside webviews;
|
||||
the original import error must reach the UI error boundary instead.
|
||||
|
||||
## Extension guideline
|
||||
|
||||
When adding new bridge route families:
|
||||
|
||||
Reference in New Issue
Block a user