getting started guide
part1. webview 기반의 extension 생성하기
webview 생성
// file: src/extension.ts
export function activate(context: vscode.ExtensionContext) {
// webview를 위한 command 등록
const helloCommand = vscode.commands.registerCommand("hello-world.helloWorld", () => {
HelloWorldPanel.render();
});
context.subscriptions.push(helloCommand);
}
webview panel class 생성
src
폴더에 panels
폴더 추가 후, 패널.ts
파일 생성
- webview panel들의 상태와 동작을 관리할 클래스 생성
- panel 생성 및 rendering
- panel 종료 시, webview resource를 cleaning up 하고 disposing
- html content 반영
- webview와 extension 간 data 전송을 위한 message listener 설정
- 생성자와 properies
- vscode API를 import하고 export 된 panel class 생성하기
// file: src/panels/HelloWorldPanel.ts
import * as vscode from "vscode";
// panel class
export class HelloWorldPanel {
// properties
public static currentPanel: HelloWorldPanel | undefined;
private readonly _panel: vscode.WebviewPanel;
private _disposables: vscode.Disposable[] = [];
// 생성자
private constructor(panel: vscode.WebviewPanel) {
this._panel = panel;
}
}
- method rendering
- rendering을 위한 method 추가하기
- webview panel을 render 하거나 webview가 없을 때는 새로 생성하는 역할
// file: src/panels/HelloWorldPanel.ts
export class HelloWorldPanel {
// ... properties and constructor method ...
// render 메서드
public static render() {
// 이미 있으면 띄우고
if (HelloWorldPanel.currentPanel) {
HelloWorldPanel.currentPanel._panel.reveal(vscode.ViewColumn.One);
} else { // 없으면 새로 생성
const panel = vscode.window.createWebviewPanel("hello-world", "Hello World", vscode.ViewColumn.One, {
// 일단은 비워두기
});
HelloWorldPanel.currentPanel = new HelloWorldPanel(panel);
}
}
}
extension.ts
파일로 돌아가서 import 선언문 추가하기
// file: src/extension.ts
import * as vscode from "vscode";
import { HelloWorldPanel } from "./panels/HelloWorldPanel";
// ... activate function ...
- Dispose method
- webview panel이 닫힐 때, clean up 역할을 하는 메서드
// file: src/panels/HelloWorldPanel.ts
export class HelloWorldPanel {
// ... other properties and methods ...
public dispose() {
// panel 초기화
HelloWorldPanel.currentPanel = undefined;
this._panel.dispose();
while (this._disposables.length) {
const disposable = this._disposables.pop();
if (disposable) {
disposable.dispose();
}
}
}
}
- 생성자 update
onDidDispose
event listener
// file: src/panels/HelloWorldPanel.ts
private constructor(panel: vscode.WebviewPanel) {
// ... other code ...
this._panel.onDidDispose(this.dispose, null, this._disposables);
}
- get webview content method
- UI가 정의될 method
- CSS와 JavaScript 파일/패키지의 reference 정의
- webview UI toolkit 설정
// file: src/panels/HelloWorldPanel.ts
export class HelloWorldPanel {
// ... other properties and methods ...
private _getWebviewContent() {
return /*html*/ `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
`;
}
}
// file: src/panels/HelloWorldPanel.ts
private constructor(panel: vscode.WebviewPanel) {
// ... other code ...
this._panel.webview.html = this._getWebviewContent();
}
npm install --save @vscode/webview-ui-toolkit
- 프로젝트 적용하기
_getWebviewContent
갱신
- 생성자 update
- 메서드 update
// file: src/panels/HelloWorldPanel.ts
// vscode.Webview형 파라미터와 vscode.Uri 파라미터
private _getWebviewContent(webview: vscode.Webview, extensionUri: vscode.Uri) {
// 일단 구현 생략
}
// file: src/panels/HelloWorldPanel.ts
// 생성자 파라미터 추가
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
// ... other code ...
// _getWebviewContent 메서드 파라미터 추가
this._panel.webview.html = this._getWebviewContent(this._panel.webview, extensionUri);
}
// file: src/panels/HelloWorldPanel.ts
// render 파라미터 추가
public static render(extensionUri: vscode.Uri) {
// ... other code ...
HelloWorldPanel.currentPanel = new HelloWorldPanel(panel, extensionUri);
}
// file: src/extension.ts
HelloWorldPanel.render(context.extensionUri);
webview uri 생성
URI(Uniform Resource Identifier)
- 특정 리소스를 식별하는 통합 자원 식별자
- 웹 기술에서 사용하는 논리적 또는 물리적 리소스를 식별하는 고유한 문자열 시퀀스
- toolkit 패키지를 가리키고 있는 uri를 생성하기 위한 vscode API 사용 가능
src
폴더에 utilities
폴더 추가 후 getUri.ts
파일 생성
// file: src/utilities/getUri.ts
// Uri 및 Webview 모듈 불러오기
import { Uri, Webview } from "vscode";
export function getUri(webview: Webview, extensionUri: Uri, pathList: string[]) {
return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList));
}
- 위 함수를 통해 webview URI 가져오기
// file: src/panels/HelloWorldPanel.ts
// uri 모듈 가져오기
import { getUri } from "../utilities/getUri";
// ... other code ...
private _getWebviewContent(webview: vscode.Webview, extensionUri: vscode.Uri) {
// webview, uri, path list
const toolkitUri = getUri(webview, extensionUri, [
"node_modules",
"@vscode",
"webview-ui-toolkit",
"dist",
"toolkit.js", // A toolkit.min.js file is also available
]);
// ... other code ...
}
webview에 URI 넘겨주기
- toolkit URI에 접근하여 webview context에 넘겨주기
// file: src/panels/HelloWorldPanel.ts
private _getWebviewContent(webview: vscode.Webview, extensionUri: vscode.Uri) {
// ... toolkit uri ...
return /*html*/ `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
// 모듈 리소스
<script type="module" src="${toolkitUri}"></script>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
`;
}
webview 설정 갱신하기
- render method 내부에서 Javascript가 동작할 수 있는 설정 on
// file: src/panels/HelloWorldPanel.ts
public static render(extensionUri: vscode.Uri) {
// ... other code ...
const panel = vscode.window.createWebviewPanel("helloworld", "Hello World", vscode.ViewColumn.One, {
// JavaScript를 동작하도록 허용
enableScripts: true,
});
// ... other code ...
}
// file: src/panels/HelloWorldPanel.ts
private _getWebviewContent(webview: vscode.Webview, extensionUri: vscode.Uri) {
// ... other code ...
return /*html*/ `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script type="module" src="${toolkitUri}"></script>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
// toolkit의 버튼을 사용한다
<vscode-button id="howdy">Howdy!</vscode-button>
</body>
</html>
`;
}
결과
- 기존 button UI가 아닌 toolkit의 파란 button UI 생성
part3. Message 전송 set up
message listener method 생성
- webveiw context로부터 message를 받는 event listener
- 전송 받은 message에 기반하여 code 실행
// file: src/panels/HelloWorldPanel.ts
export class HelloWorldPanel {
// ... other properties and methods ...
private _setWebviewMessageListener(webview: vscode.Webview) {
// message 받기
webview.onDidReceiveMessage(
(message: any) => {
// command와 내용
const command = message.command;
const text = message.text;
switch (command) {
case "hello":
// 실행할 코드
vscode.window.showInformationMessage(text);
return;
}
},
undefined,
this._disposables
);
}
}
// file: src/panels/HelloWorldPanel.ts
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
// ... other code ...
this._setWebviewMessageListener(this._panel.webview);
}
message 전송 code 생성하기
main.js
파일에 정의
<vscode-button>
이 클릭될 때마다 message 전송
webview-ui
폴더 추가 후, main.js
파일 생성
// file: webview-ui/main.js
const vscode = acquireVsCodeApi();
window.addEventListener("load", main);
function main() {
// id를 통해 식별
const howdyButton = document.getElementById("howdy");
// eventlistener
howdyButton.addEventListener("click", handleHowdyClick);
}
// 전송될 message
function handleHowdyClick() {
vscode.postMessage({
command: "hello",
text: "Hey there partner! 🤠",
});
}
- URI 생성 및 webview HTML에 전송
// file: src/panels/HelloWorldPanel.ts
private _getWebviewContent(webview: vscode.Webview, extensionUri: vscode.Uri) {
// ... other code ...
// uri 가져오기
const mainUri = getUri(webview, extensionUri, ["webview-ui", "main.js"]);
return /*html*/ `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script type="module" src="${toolkitUri}"></script>
// uri를 위한 script
<script type="module" src="${mainUri}"></script>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<vscode-button id="howdy">Howdy!</vscode-button>
</body>
</html>
`;
}
결과