diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 00aa85761895c..e2a484ad05e99 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -113,24 +113,30 @@ class WebviewSession extends Disposable { } class WebviewProtocolProvider extends Disposable { + + private _resolve!: () => void; + private _reject!: () => void; + + public readonly ready: Promise; + constructor( handle: WebviewTagHandle, - private readonly _getExtensionLocation: () => URI | undefined, - private readonly _getLocalResourceRoots: () => ReadonlyArray, - private readonly _fileService: IFileService, + getExtensionLocation: () => URI | undefined, + getLocalResourceRoots: () => ReadonlyArray, + fileService: IFileService, ) { super(); + this.ready = new Promise((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + this._register(handle.onFirstLoad(contents => { - this.registerProtocols(contents); + registerFileProtocol(contents, WebviewResourceScheme, fileService, getExtensionLocation(), getLocalResourceRoots) + .then(this._resolve, this._reject); })); } - - private registerProtocols(contents: WebContents) { - registerFileProtocol(contents, WebviewResourceScheme, this._fileService, this._getExtensionLocation(), () => - this._getLocalResourceRoots() - ); - } } class WebviewPortMappingProvider extends Disposable { @@ -204,6 +210,7 @@ export class ElectronWebviewBasedWebview extends BaseWebview impleme private _findStarted: boolean = false; public extension: WebviewExtensionDescription | undefined; + private readonly _protocolProvider: WebviewProtocolProvider; constructor( id: string, @@ -222,11 +229,12 @@ export class ElectronWebviewBasedWebview extends BaseWebview impleme const webviewAndContents = this._register(new WebviewTagHandle(this.element!)); const session = this._register(new WebviewSession(webviewAndContents)); - this._register(new WebviewProtocolProvider( - webviewAndContents, - () => this.extension ? this.extension.location : undefined, - () => (this.content.options.localResourceRoots || []), - fileService)); + this._protocolProvider = new WebviewProtocolProvider + (webviewAndContents, + () => this.extension ? this.extension.location : undefined, + () => (this.content.options.localResourceRoots || []), + fileService); + this._register(this._protocolProvider); this._register(new WebviewPortMappingProvider( session, @@ -322,7 +330,8 @@ export class ElectronWebviewBasedWebview extends BaseWebview impleme parent.appendChild(this.element); } - protected postMessage(channel: string, data?: any): void { + protected async postMessage(channel: string, data?: any): Promise { + await this._protocolProvider.ready; this.element?.send(channel, data); } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts index e84ce9bf6fbcb..39e4349cb40ce 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts @@ -14,24 +14,27 @@ export function registerFileProtocol( extensionLocation: URI | undefined, getRoots: () => ReadonlyArray ) { - contents.session.protocol.registerBufferProtocol(protocol, async (request, callback: any) => { - try { - const result = await loadLocalResource(URI.parse(request.url), fileService, extensionLocation, getRoots); - if (result.type === WebviewResourceResponse.Type.Success) { - return callback({ - data: Buffer.from(result.data.buffer), - mimeType: result.mimeType - }); + return new Promise((resolve, reject) => + contents.session.protocol.registerBufferProtocol(protocol, async (request, callback: any) => { + try { + const result = await loadLocalResource(URI.parse(request.url), fileService, extensionLocation, getRoots); + if (result.type === WebviewResourceResponse.Type.Success) { + return callback({ + data: Buffer.from(result.data.buffer), + mimeType: result.mimeType + }); + } + if (result.type === WebviewResourceResponse.Type.AccessDenied) { + console.error('Webview: Cannot load resource outside of protocol root'); + return callback({ error: -10 /* ACCESS_DENIED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ }); + } + } catch { + // noop } - if (result.type === WebviewResourceResponse.Type.AccessDenied) { - console.error('Webview: Cannot load resource outside of protocol root'); - return callback({ error: -10 /* ACCESS_DENIED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ }); - } - } catch { - // noop - } - return callback({ error: -2 /* FAILED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ }); - }); + return callback({ error: -2 /* FAILED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ }); + }, (err) => { + err ? reject(err) : resolve(); + })); }