To begin, generate a production build using webpack to serve as the content for your webview. Since loading the webview directly from a URL is not feasible, you will need to insert an iframe and load it from the URL instead.
protected createPanel(caption: string, url: URL, placement?: string): Promise<boolean> {
return new Promise((resolve) => {
const viewColumn = (!placement || placement === "Active") ? ViewColumn.Active : ViewColumn.Beside;
if (placement === "Beside Bottom") {
void commands.executeCommand("workbench.action.editorLayoutTwoRows");
}
this.panel = window.createWebviewPanel(
"the-webview", caption, viewColumn, {
enableScripts: true,
retainContextWhenHidden: true,
},
);
this.panel.onDidDispose(() => { this.handleDispose(); });
this.panel.webview.onDidReceiveMessage((message: IEmbeddedMessage) => {
if (message.source === "app") {
// Handle webview messages here.
}
});
// Insert an iframe to load the external URL.
this.panel.webview.html = `
<!doctype html><html lang="en">
<head>
<meta http-equiv="Content-Security-Policy" content="default-src *; img-src http: https:;
script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'unsafe-inline' http: https: data: *;">
</head>
<body style="margin:0px;padding:0px;overflow:hidden;">
<iframe id="frame:${caption}"
src="${url.toString()}"
frameborder="0" style="overflow: hidden; overflow-x: hidden; overflow-y: hidden; height:100%;
width:100%; position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px" height="100%"
width="100%">
</iframe>
<script>
let frame;
let vscode;
window.addEventListener('message', (event) => {
if (!frame) {
vscode = acquireVsCodeApi();
frame = document.getElementById("frame:${caption}");
}
if (event.data.source === "host") {
// Forward message from the extension to the iframe.
frame.contentWindow.postMessage(event.data, "*");
} else if (event.data.source === "app") {
// Forward messages from the iframe to the extension.
vscode.postMessage(event.data);
} else {
// Forward certain messages to our parent window, which will further forward to vscode.
switch (event.data.type) {
case "keydown": {
window.dispatchEvent(new KeyboardEvent("keydown", event.data));
break;
}
case "keyup": {
window.dispatchEvent(new KeyboardEvent("keyup", event.data));
break;
}
}
}
});
</script>
</body></html>
`;
});
}
The webview itself functions as an iframe, with message handling already established between it and vscode. However, for any additional iframe, a similar approach must be taken to forward messages either from your app code to vscode or vice versa. In my implementation, I use a field in the transmitted data to determine the direction of forwarding.