Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
run: npm run build:netlify
- name: Deploy demo preview to Netlify
if: github.event.pull_request.head.repo.full_name == github.repository && env.NETLIFY_AUTH_TOKEN != '' && env.NETLIFY_SITE_ID != ''
uses: nwtgck/actions-netlify@v3.0
uses: nwtgck/actions-netlify@v4.0
with:
publish-dir: './demo/dist'
production-branch: ${{ github.event.repository.default_branch }}
Expand Down
13 changes: 12 additions & 1 deletion demo/src/setup.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,22 @@ export const envOptions: EnvironmentOverride = {
userHome: vscode.Uri.file('/')
}

const alternateDomainPatternUrl = new URL('.', import.meta.url)
alternateDomainPatternUrl.pathname = ''

// Only localhost supports subdomains, netlify doesn't
if (alternateDomainPatternUrl.hostname.includes('localhost')) {
alternateDomainPatternUrl.hostname = `{{uuid}}.${alternateDomainPatternUrl.hostname}`
}

export let alternateDomainPattern = alternateDomainPatternUrl.href

export const commonServices: IEditorOverrideServices = {
...getAuthenticationServiceOverride(),
...getLogServiceOverride(),
...getExtensionServiceOverride({
enableWorkerExtensionHost: true
enableWorkerExtensionHost: true,
iframeAlternateDomain: alternateDomainPattern
}),
...getExtensionGalleryServiceOverride({ webOnly: false }),
...getModelServiceOverride(),
Expand Down
3 changes: 2 additions & 1 deletion demo/src/setup.views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { setUnexpectedErrorHandler } from '@codingame/monaco-vscode-api/monaco'
import { openNewCodeEditor } from './features/editor'
import './features/customView.views'
import {
alternateDomainPattern,
commonServices,
constructOptions,
envOptions,
Expand Down Expand Up @@ -81,7 +82,7 @@ document.body.append(container)
await initializeMonacoService(
{
...commonServices,
...getViewsServiceOverride(openNewCodeEditor, undefined),
...getViewsServiceOverride(openNewCodeEditor, alternateDomainPattern),

...getQuickAccessServiceOverride({
isKeybindingConfigurationVisible: isEditorPartVisible,
Expand Down
5 changes: 3 additions & 2 deletions demo/src/setup.workbench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
envOptions,
remoteAuthority,
userDataProvider,
disableShadowDom
disableShadowDom,
alternateDomainPattern
} from './setup.common'

let container = window.vscodeContainer
Expand Down Expand Up @@ -60,7 +61,7 @@ document.body.append(buttons)
await initializeMonacoService(
{
...commonServices,
...getWorkbenchServiceOverride(),
...getWorkbenchServiceOverride(undefined, alternateDomainPattern),
...getQuickAccessServiceOverride({
isKeybindingConfigurationVisible: () => true,
shouldUseGlobalPicker: () => true
Expand Down
3 changes: 3 additions & 0 deletions demo/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export default defineConfig({
enforce: 'pre',
async resolveId(source, importer, options) {
const resolved = (await this.resolve(source, importer, options))!
if (resolved == null) {
throw new Error(`Unable to resolve: ${source} from ${importer}`)
}
if (
resolved.id.match(
/node_modules\/(@codingame\/monaco-vscode|vscode|monaco-editor).*\.css$/
Expand Down
34 changes: 28 additions & 6 deletions vscode-patches/0026-fix-use-asBrowserUri-to-get-iframe-src.patch
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ Date: Mon, 11 Mar 2024 18:21:20 +0100
Subject: [PATCH] fix: use asBrowserUri to get iframe src

---
src/vs/workbench/contrib/webview/browser/webviewElement.ts | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
.../contrib/webview/browser/webviewElement.ts | 22 +++++--------------
1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
index 4e073206a68..c64dffc458c 100644
index 4e073206a68..d9b32146d27 100644
--- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts
+++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
@@ -13,9 +13,9 @@ import { CancellationToken, CancellationTokenSource } from '../../../../base/com
Expand All @@ -22,15 +22,37 @@ index 4e073206a68..c64dffc458c 100644
import { URI } from '../../../../base/common/uri.js';
import { generateUuid } from '../../../../base/common/uuid.js';
import { localize } from '../../../../nls.js';
@@ -467,8 +467,9 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
@@ -467,8 +467,11 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
const queryString = new URLSearchParams(params).toString();

this.perfMark('init/set-src');
- const fileName = 'index.html';
- this.element!.setAttribute('src', `${this.webviewContentEndpoint(encodedWebviewOrigin)}/${fileName}?${queryString}`);
+
+ const relativeIframeSrc = FileAccess.asBrowserUri(`vs/workbench/contrib/webview/browser/pre/index.html`);
+ this.element!.setAttribute('src', `${relativeIframeSrc.toString(true)}?${queryString}`);
+ const relativeIframeSrc = FileAccess.asBrowserUri(`vs/workbench/contrib/webview/browser/pre/index.html`)
+ .toString(true)
+ .replace('{{uuid}}', encodedWebviewOrigin);
+ this.element!.setAttribute('src', `${relativeIframeSrc}?${queryString}`);
}

public mountTo(element: HTMLElement, targetWindow: CodeWindow) {
@@ -563,19 +566,6 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
}
}

- protected webviewContentEndpoint(encodedWebviewOrigin: string): string {
- const webviewExternalEndpoint = this._environmentService.webviewExternalEndpoint;
- if (!webviewExternalEndpoint) {
- throw new Error(`'webviewExternalEndpoint' has not been configured. Webviews will not work!`);
- }
-
- const endpoint = webviewExternalEndpoint.replace('{{uuid}}', encodedWebviewOrigin);
- if (endpoint[endpoint.length - 1] === '/') {
- return endpoint.slice(0, endpoint.length - 1);
- }
- return endpoint;
- }
-
private doPostMessage(channel: string, data?: any, transferable: Transferable[] = []): boolean {
if (this.element && this._messagePort) {
this._messagePort.postMessage({ channel, args: data }, transferable);
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Date: Mon, 11 Mar 2024 18:21:40 +0100
Subject: [PATCH] feat: add some parameter to webview iframes

---
src/vs/workbench/contrib/webview/browser/pre/index.html | 6 ++++--
src/vs/workbench/contrib/webview/browser/webviewElement.ts | 3 +++
2 files changed, 7 insertions(+), 2 deletions(-)
.../contrib/webview/browser/pre/index.html | 6 ++++--
.../contrib/webview/browser/webviewElement.ts | 15 +++++++++++----
2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html
index 1b722167644..39088a04919 100644
Expand Down Expand Up @@ -40,16 +40,41 @@ index 1b722167644..39088a04919 100644
newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden';
document.body.appendChild(newFrame);
diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
index c64dffc458c..69e5c9244b2 100644
index d9b32146d27..4e7b69bd139 100644
--- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts
+++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
@@ -462,6 +462,9 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
@@ -15,7 +15,7 @@ import { Lazy } from '../../../../base/common/lazy.js';
import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
import { observableValue } from '../../../../base/common/observable.js';
import { listenStream } from '../../../../base/common/stream.js';
-import { COI, FileAccess } from '../../../../base/common/network.js';
+import { AppResourcePath, COI, FileAccess } from '../../../../base/common/network.js';
import { URI } from '../../../../base/common/uri.js';
import { generateUuid } from '../../../../base/common/uuid.js';
import { localize } from '../../../../nls.js';
@@ -462,15 +462,22 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
params.purpose = options.purpose;
}

+ params.serviceWorkerUri = FileAccess.asBrowserUri('vs/workbench/contrib/webview/browser/pre/service-worker.js').toString(true);
+ params.fakeHtmlUri = FileAccess.asBrowserUri('vs/workbench/contrib/webview/browser/pre/fake.html').toString(true);
+ const asBrowserUri = (uri: AppResourcePath) => {
+ return FileAccess.asBrowserUri(uri)
+ .toString(true)
+ .replace('{{uuid}}', encodedWebviewOrigin);
+ };
+
+ params.serviceWorkerUri = asBrowserUri('vs/workbench/contrib/webview/browser/pre/service-worker.js');
+ params.fakeHtmlUri = asBrowserUri('vs/workbench/contrib/webview/browser/pre/fake.html');
+
COI.addSearchParam(params, true, true);

const queryString = new URLSearchParams(params).toString();

this.perfMark('init/set-src');

- const relativeIframeSrc = FileAccess.asBrowserUri(`vs/workbench/contrib/webview/browser/pre/index.html`)
- .toString(true)
- .replace('{{uuid}}', encodedWebviewOrigin);
+ const relativeIframeSrc = asBrowserUri(`vs/workbench/contrib/webview/browser/pre/index.html`);
this.element!.setAttribute('src', `${relativeIframeSrc}?${queryString}`);
}

6 changes: 3 additions & 3 deletions vscode-patches/0060-feat-support-shadow-dom.patch
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,7 @@ index 9a745727415..32b87509ab3 100644
const listener = this._register(Event.once(this._terminalService.onDidChangeConnectionState)(() => {
// Only focus the terminal if the activeElement has not changed since focus() was called
diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
index 69e5c9244b2..40a109760c3 100644
index 4e7b69bd139..5455eea1f88 100644
--- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts
+++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
@@ -4,7 +4,7 @@
Expand All @@ -1386,7 +1386,7 @@ index 69e5c9244b2..40a109760c3 100644
// looks like https://github.com/microsoft/vscode/issues/132641
// where the focus is actually not in the `<iframe>`
return false;
@@ -712,7 +713,7 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
@@ -705,7 +706,7 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
}

private isActiveElement(): boolean {
Expand All @@ -1395,7 +1395,7 @@ index 69e5c9244b2..40a109760c3 100644
}

private handleKeyEvent(type: 'keydown' | 'keyup', event: KeyEvent) {
@@ -961,8 +962,11 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
@@ -954,8 +955,11 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6485,7 +6485,7 @@ index a2230caed6f..ed26b072827 100644
}

diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
index 40a109760c3..d48d3d081de 100644
index 5455eea1f88..03e5cf3eca5 100644
--- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts
+++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
@@ -4,7 +4,7 @@
Expand All @@ -6503,7 +6503,7 @@ index 40a109760c3..d48d3d081de 100644
import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
-import { observableValue } from '../../../../base/common/observable.js';
import { listenStream } from '../../../../base/common/stream.js';
import { COI, FileAccess } from '../../../../base/common/network.js';
import { AppResourcePath, COI, FileAccess } from '../../../../base/common/network.js';
+import { observableValue } from '../../../../base/common/observable.js';
import { URI } from '../../../../base/common/uri.js';
import { generateUuid } from '../../../../base/common/uuid.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Mangeonjean?= <loic@coderpad.io>
Date: Tue, 25 Aug 2026 11:32:53 +0200
Subject: [PATCH] feat: support using a unique subdomain for the extHost iframe

---
.../browser/webWorkerExtensionHost.ts | 25 ++++++++++++-------
1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts
index d62f61b75c1..865a01a6b53 100644
--- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts
+++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts
@@ -97,18 +97,21 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
const webEndpointUrlTemplate = this._productService.webEndpointUrlTemplate;
const commit = this._productService.commit;
const quality = this._productService.quality;
+
+ // Try to keep the web worker extension host iframe origin stable by storing it in workspace storage
+ const key = 'webWorkerExtensionHostIframeStableOriginUUID';
+ let stableOriginUUID = this._storageService.get(key, StorageScope.WORKSPACE);
+ if (typeof stableOriginUUID === 'undefined') {
+ stableOriginUUID = generateUuid();
+ this._storageService.store(key, stableOriginUUID, StorageScope.WORKSPACE, StorageTarget.MACHINE);
+ }
+ const hash = await parentOriginHash(mainWindow.origin, stableOriginUUID);
+ const uuid = `v--${hash}`; // using `v--` as a marker to require `parentOrigin`/`salt` verification
+
if (webEndpointUrlTemplate && commit && quality) {
- // Try to keep the web worker extension host iframe origin stable by storing it in workspace storage
- const key = 'webWorkerExtensionHostIframeStableOriginUUID';
- let stableOriginUUID = this._storageService.get(key, StorageScope.WORKSPACE);
- if (typeof stableOriginUUID === 'undefined') {
- stableOriginUUID = generateUuid();
- this._storageService.store(key, stableOriginUUID, StorageScope.WORKSPACE, StorageTarget.MACHINE);
- }
- const hash = await parentOriginHash(mainWindow.origin, stableOriginUUID);
const baseUrl = (
webEndpointUrlTemplate
- .replace('{{uuid}}', `v--${hash}`) // using `v--` as a marker to require `parentOrigin`/`salt` verification
+ .replace('{{uuid}}', uuid) // using `v--` as a marker to require `parentOrigin`/`salt` verification
.replace('{{commit}}', commit)
.replace('{{quality}}', quality)
);
@@ -116,6 +119,10 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
const res = new URL(`${baseUrl}/out/${iframeModulePath}${suffix}`);
res.searchParams.set('salt', stableOriginUUID);
return res.toString();
+ } else {
+ const relativeExtensionHostIframeSrc = FileAccess.asBrowserUri(iframeModulePath).toString(true);
+
+ return `${relativeExtensionHostIframeSrc.replace('{{uuid}}', uuid)}${suffix}`;
}
}

31 changes: 31 additions & 0 deletions vscode-patches/0106-fix-stop-disabling-browser-cache.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Mangeonjean?= <loic@coderpad.io>
Date: Tue, 25 Aug 2026 11:41:33 +0200
Subject: [PATCH] fix: stop disabling browser cache

---
src/vs/workbench/contrib/webview/browser/pre/index.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html
index 3b8322bcd40..928ebe537d4 100644
--- a/src/vs/workbench/contrib/webview/browser/pre/index.html
+++ b/src/vs/workbench/contrib/webview/browser/pre/index.html
@@ -5,7 +5,7 @@
<meta charset="UTF-8">

<meta http-equiv="Content-Security-Policy"
- content="default-src 'none'; script-src 'sha256-w0KUwxUBD3iVNe1RE1K2jxHs0Cvg8zpd/Yez4nydyvs=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
+ content="default-src 'none'; script-src 'sha256-p5SngML9tF1lOPin4w0KJSw74GFxDJyEfTyvPhrzldo=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">

<!-- Disable pinch zooming -->
<meta name="viewport"
@@ -255,7 +255,7 @@
}

const swPath = encodeURI(`${serviceWorkerUri}?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}`);
- navigator.serviceWorker.register(swPath, { type: 'module', updateViaCache: 'none' })
+ navigator.serviceWorker.register(swPath, { type: 'module' })
.then(async registration => {
if (navigator.serviceWorker.controller) {
// A previous SW is already controlling. Force an update