diff --git a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts index da0789fab36..8ea57336612 100644 --- a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts +++ b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts @@ -135,7 +135,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { async $postMessage(handle: number, value: any): Promise { const inset = this.getInset(handle); - inset.webview.sendMessage(value); + inset.webview.postMessage(value); return true; } diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/browser/mainThreadWebview.ts index b3e766e4cba..0240c478525 100644 --- a/src/vs/workbench/api/browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/browser/mainThreadWebview.ts @@ -252,7 +252,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma public async $postMessage(handle: extHostProtocol.WebviewPanelHandle, message: any): Promise { const webview = this.getWebviewInput(handle); - webview.webview.sendMessage(message); + webview.webview.postMessage(message); return true; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 29473bb9b91..c029b3259d2 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1193,7 +1193,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } postMessage(message: any) { - this.webview?.webview.sendMessage(message); + this.webview?.webview.postMessage(message); } //#endregion diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index f282a7ac20d..dc0daa654c5 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -714,7 +714,7 @@ ${loaderJs} } private _sendMessageToWebview(message: ToWebviewMessage) { - this.webview.sendMessage(message); + this.webview.postMessage(message); } clearPreloadsCache() { diff --git a/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts b/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts index 8bcb458cb43..0c12198ddfb 100644 --- a/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts @@ -48,6 +48,22 @@ interface WebviewContent { readonly state: string | undefined; } +namespace WebviewState { + export const enum Type { Initializing, Ready } + + export class Initializing { + readonly type = Type.Initializing; + + constructor( + public readonly pendingMessages: Array<{ readonly channel: string, readonly data?: any }> + ) { } + } + + export const Ready = { type: Type.Ready } as const; + + export type State = typeof Ready | Initializing; +} + export abstract class BaseWebview extends Disposable { private _element: T | undefined; @@ -56,11 +72,10 @@ export abstract class BaseWebview extends Disposable { private _focused: boolean | undefined; protected get focused(): boolean { return !!this._focused; } - private readonly _ready: Promise; + private _state: WebviewState.State = new WebviewState.Initializing([]); protected content: WebviewContent; - constructor( // TODO: matb, this should not be protected. The only reason it needs to be is that the base class ends up using it in the call to createElement protected readonly id: string, @@ -82,15 +97,18 @@ export abstract class BaseWebview extends Disposable { this._element = this.createElement(options, contentOptions); - this._ready = new Promise(resolve => { - const subscription = this._register(this.on(WebviewMessageChannels.webviewReady, () => { - if (this.element) { - addClass(this.element, 'ready'); - } - subscription.dispose(); - resolve(); - })); - }); + const subscription = this._register(this.on(WebviewMessageChannels.webviewReady, () => { + if (this.element) { + addClass(this.element, 'ready'); + } + + if (this._state.type === WebviewState.Type.Initializing) { + this._state.pendingMessages.forEach(({ channel, data }) => this.doPostMessage(channel, data)); + } + this._state = WebviewState.Ready; + + subscription.dispose(); + })); this._register(this.on('no-csp-found', () => { this.handleNoCspFound(); @@ -176,14 +194,16 @@ export abstract class BaseWebview extends Disposable { private readonly _onDidBlur = this._register(new Emitter()); public readonly onDidBlur = this._onDidBlur.event; - public sendMessage(data: any): void { + public postMessage(data: any): void { this._send('message', data); } protected _send(channel: string, data?: any): void { - this._ready - .then(() => this.postMessage(channel, data)) - .catch(err => console.error(err)); + if (this._state.type === WebviewState.Type.Initializing) { + this._state.pendingMessages.push({ channel, data }); + } else { + this.doPostMessage(channel, data); + } } protected abstract readonly extraContentOptions: { readonly [key: string]: string }; @@ -192,7 +212,7 @@ export abstract class BaseWebview extends Disposable { protected abstract on(channel: string, handler: (data: T) => void): IDisposable; - protected abstract postMessage(channel: string, data?: any): void; + protected abstract doPostMessage(channel: string, data?: any): void; private _hasAlertedAboutMissingCsp = false; private handleNoCspFound(): void { diff --git a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts index 47796703208..00818b92b0c 100644 --- a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts +++ b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts @@ -142,7 +142,7 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewOv this._onDidUpdateState.fire(state); })); - this._pendingMessages.forEach(msg => webview.sendMessage(msg)); + this._pendingMessages.forEach(msg => webview.postMessage(msg)); this._pendingMessages.clear(); } this.container.style.visibility = 'visible'; @@ -203,9 +203,9 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewOv private readonly _onMissingCsp = this._register(new Emitter()); public readonly onMissingCsp: Event = this._onMissingCsp.event; - sendMessage(data: any): void { + postMessage(data: any): void { if (this._webview.value) { - this._webview.value.sendMessage(data); + this._webview.value.postMessage(data); } else { this._pendingMessages.add(data); } diff --git a/src/vs/workbench/contrib/webview/browser/webview.ts b/src/vs/workbench/contrib/webview/browser/webview.ts index b3e87e7fa83..1d359d78f52 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.ts @@ -96,7 +96,7 @@ export interface Webview extends IDisposable { readonly onMessage: Event; readonly onMissingCsp: Event; - sendMessage(data: any): void; + postMessage(data: any): void; focus(): void; reload(): void; diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index c557d5ba4c6..d629a6165fd 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -163,7 +163,7 @@ export class IFrameWebview extends BaseWebview implements Web }); } - protected postMessage(channel: string, data?: any): void { + protected doPostMessage(channel: string, data?: any): void { if (this.element) { this.element.contentWindow!.postMessage({ channel, args: data }, '*'); } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index c81759c187b..6df573e39fa 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -434,7 +434,7 @@ export class ElectronWebviewBasedWebview extends BaseWebview impleme parent.appendChild(this.element); } - protected async postMessage(channel: string, data?: any): Promise { + protected async doPostMessage(channel: string, data?: any): Promise { await Promise.all([ this._protocolProvider.synchronize(), this._domReady,