Code snippets for answer to SO question
Last active
September 26, 2022 21:26
-
-
Save AWolf81/c0fef6435487c989cd84811dd7973643 to your computer and use it in GitHub Desktop.
VS Code Webview example (Provider with postMessage)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//media\main.js | |
//@ts-check | |
// This script will be run within the webview itself | |
// It cannot access the main VS Code APIs directly. | |
(function () { | |
const handleExtensionMessages = (event) => { | |
const { message, type } = event.data; | |
switch (type) { | |
case 'greeting': | |
console.log("received", message); | |
break; | |
} | |
}; | |
window.addEventListener("message", handleExtensionMessages); | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html { | |
box-sizing: border-box; | |
font-size: 13px; | |
} | |
*, | |
*:before, | |
*:after { | |
box-sizing: inherit; | |
} | |
body, | |
h1, | |
h2, | |
h3, | |
h4, | |
h5, | |
h6, | |
p, | |
ol, | |
ul { | |
margin: 0; | |
padding: 0; | |
font-weight: normal; | |
} | |
img { | |
max-width: 100%; | |
height: auto; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:root { | |
--container-paddding: 20px; | |
--input-padding-vertical: 6px; | |
--input-padding-horizontal: 4px; | |
--input-margin-vertical: 4px; | |
--input-margin-horizontal: 0; | |
} | |
body { | |
padding: 0 var(--container-paddding); | |
color: var(--vscode-foreground); | |
font-size: var(--vscode-font-size); | |
font-weight: var(--vscode-font-weight); | |
font-family: var(--vscode-font-family); | |
background-color: var(--vscode-editor-background); | |
} | |
ol, | |
ul { | |
padding-left: var(--container-paddding); | |
} | |
body > *, | |
form > * { | |
margin-block-start: var(--input-margin-vertical); | |
margin-block-end: var(--input-margin-vertical); | |
} | |
*:focus { | |
outline-color: var(--vscode-focusBorder) !important; | |
} | |
a { | |
color: var(--vscode-textLink-foreground); | |
} | |
a:hover, | |
a:active { | |
color: var(--vscode-textLink-activeForeground); | |
} | |
code { | |
font-size: var(--vscode-editor-font-size); | |
font-family: var(--vscode-editor-font-family); | |
} | |
button { | |
border: none; | |
padding: var(--input-padding-vertical) var(--input-padding-horizontal); | |
width: 100%; | |
text-align: center; | |
outline: 1px solid transparent; | |
outline-offset: 2px !important; | |
color: var(--vscode-button-foreground); | |
background: var(--vscode-button-background); | |
} | |
button:hover { | |
cursor: pointer; | |
background: var(--vscode-button-hoverBackground); | |
} | |
button:focus { | |
outline-color: var(--vscode-focusBorder); | |
} | |
button.secondary { | |
color: var(--vscode-button-secondaryForeground); | |
background: var(--vscode-button-secondaryBackground); | |
} | |
button.secondary:hover { | |
background: var(--vscode-button-secondaryHoverBackground); | |
} | |
input:not([type='checkbox']), | |
textarea { | |
display: block; | |
width: 100%; | |
border: none; | |
font-family: var(--vscode-font-family); | |
padding: var(--input-padding-vertical) var(--input-padding-horizontal); | |
color: var(--vscode-input-foreground); | |
outline-color: var(--vscode-input-border); | |
background-color: var(--vscode-input-background); | |
} | |
input::placeholder, | |
textarea::placeholder { | |
color: var(--vscode-input-placeholderForeground); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "webview-provider-example", | |
"displayName": "webview-provider-example", | |
"description": "", | |
"version": "0.0.1", | |
"engines": { | |
"vscode": "^1.71.0" | |
}, | |
"categories": [ | |
"Other" | |
], | |
"activationEvents": [ | |
"onView:myExtension.controlsView", | |
"onCommand:myExtension.sayHello" | |
], | |
"main": "./out/extension.js", | |
"contributes": { | |
"views": { | |
"explorer": [ | |
{ | |
"type": "webview", | |
"id": "myExtension.controlsView", | |
"name": "MyExtension" | |
} | |
] | |
}, | |
"commands": [ | |
{ | |
"command": "myExtension.sayHello", | |
"category": "myExtension", | |
"title": "SayHello" | |
} | |
] | |
}, | |
"scripts": { | |
"vscode:prepublish": "npm run compile", | |
"compile": "tsc -p ./", | |
"watch": "tsc -watch -p ./", | |
"pretest": "npm run compile && npm run lint", | |
"lint": "eslint src --ext ts", | |
"test": "node ./out/test/runTest.js" | |
}, | |
"devDependencies": { | |
"@types/vscode": "^1.71.0", | |
"@types/glob": "^7.2.0", | |
"@types/mocha": "^9.1.1", | |
"@types/node": "16.x", | |
"@typescript-eslint/eslint-plugin": "^5.31.0", | |
"@typescript-eslint/parser": "^5.31.0", | |
"eslint": "^8.20.0", | |
"glob": "^8.0.3", | |
"mocha": "^10.0.0", | |
"typescript": "^4.7.4", | |
"@vscode/test-electron": "^2.1.5" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The module 'vscode' contains the VS Code extensibility API | |
// Import the module and reference it with the alias vscode in your code below | |
import * as vscode from 'vscode'; | |
import { WebViewProvider } from './WebViewProvider'; | |
// this method is called when your extension is activated | |
// your extension is activated the very first time the command is executed | |
export function activate(context: vscode.ExtensionContext) { | |
const provider = new WebViewProvider(context.extensionUri); | |
context.subscriptions.push( | |
vscode.commands.registerCommand('myExtension.sayHello', () => { | |
// The code you place here will be executed every time your command is executed | |
// Display a message box to the user | |
// vscode.window.showInformationMessage(output); | |
provider.postMessageToWebview({ | |
type: 'greeting', | |
message: 'HelloWorld', | |
}); | |
}), | |
); | |
context.subscriptions.push( | |
vscode.window.registerWebviewViewProvider( | |
WebViewProvider.viewType, | |
provider, | |
), | |
); | |
} | |
// this method is called when your extension is deactivated | |
export function deactivate() {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as vscode from 'vscode'; | |
function getNonce() { | |
let text = ""; | |
const possible = | |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |
for (let i = 0; i < 32; i++) { | |
text += possible.charAt(Math.floor(Math.random() * possible.length)); | |
} | |
return text; | |
} | |
export class WebViewProvider | |
implements vscode.WebviewViewProvider | |
{ | |
public static readonly viewType = 'myExtension.controlsView'; | |
private _view?: vscode.WebviewView; | |
constructor(private readonly _extensionUri: vscode.Uri) { | |
} | |
public postMessageToWebview(message: any) { | |
this._view?.webview.postMessage(message); | |
} | |
public resolveWebviewView( | |
webviewView: vscode.WebviewView, | |
context: vscode.WebviewViewResolveContext, | |
_token: vscode.CancellationToken, | |
) { | |
this._view = webviewView; // needed so we can use it in postMessageToWebview later | |
webviewView.webview.options = { | |
// Allow scripts in the webview | |
enableScripts: true, | |
localResourceRoots: [this._extensionUri], | |
}; | |
webviewView.webview.html = this._getHtmlForWebview( | |
webviewView.webview, | |
); | |
webviewView.webview.onDidReceiveMessage((data) => { | |
switch (data.type) { | |
// other message types ... | |
case 'onYourEvent': { | |
console.log(data.value); // see below webview to extension communication snippet | |
break; | |
} | |
case 'onInfo': { | |
if (!data.value) { | |
return; | |
} | |
vscode.window.showInformationMessage(data.value); | |
break; | |
} | |
case 'onError': { | |
if (!data.value) { | |
return; | |
} | |
vscode.window.showErrorMessage(data.value); | |
break; | |
} | |
} | |
}); | |
} | |
private _getHtmlForWebview(webview: vscode.Webview) { | |
// // And the uri we use to load this script in the webview | |
// const scriptUri = webview.asWebviewUri( | |
// vscode.Uri.joinPath( | |
// this._extensionUri, | |
// 'out', | |
// 'svelte-app/bundle.js', | |
// ), | |
// ); | |
const scriptUri = webview.asWebviewUri( | |
vscode.Uri.joinPath(this._extensionUri, "media", "main.js") | |
); | |
// Local path to css styles | |
const styleResetPath = vscode.Uri.joinPath( | |
this._extensionUri, | |
'media', | |
'reset.css', | |
); | |
const stylesPathMainPath = vscode.Uri.joinPath( | |
this._extensionUri, | |
'media', | |
'vscode.css', | |
); | |
// Uri to load styles into webview | |
const stylesResetUri = webview.asWebviewUri(styleResetPath); | |
const stylesMainUri = webview.asWebviewUri(stylesPathMainPath); | |
// const cssUri = webview.asWebviewUri( | |
// vscode.Uri.joinPath( | |
// this._extensionUri, | |
// 'out/svelte-app', | |
// 'bundle.css', | |
// ), | |
// vscode.Uri.joinPath(this._extensionUri, "media", "main.css") | |
// ); | |
// Use a nonce to only allow specific scripts to be run | |
const nonce = getNonce(); | |
return `<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<!-- | |
Use a content security policy to only allow loading images from https or from our extension directory, | |
and only allow scripts that have a specific nonce. | |
--> | |
<meta http-equiv="Content-Security-Policy" content="img-src https: data:; style-src 'unsafe-inline' ${webview.cspSource}; script-src 'nonce-${nonce}';"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<link href="${stylesResetUri}" rel="stylesheet"> | |
<link href="${stylesMainUri}" rel="stylesheet"> | |
<script nonce="${nonce}"> | |
const tsvscode = acquireVsCodeApi(); | |
</script> | |
</head> | |
<body> | |
<h1>My Extension</h1> | |
</body> | |
<script nonce="${nonce}" src="${scriptUri}"></script> | |
</html>`; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment