[근무 일지] VS Code Extension 스터디3

타키탸키·2022년 5월 2일
1

근무 일지

목록 보기
13/16

VSCode-WebViw-UI-Toolkit


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
      • webview panel이 닫힐 때 실행
// 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 정의
      • HTML에 적용
    • 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>
    `;
  }
}
  • 생성자 update
    • HTML에 적용
// file: src/panels/HelloWorldPanel.ts

private constructor(panel: vscode.WebviewPanel) {
    // ... other code ...

    this._panel.webview.html = this._getWebviewContent();
}

part2. toolkit 설치 및 set up

  • toolkit 설치
npm install --save @vscode/webview-ui-toolkit

webview 안에서 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);
}
  • extension.ts에도 적용
// 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에 넘겨주기
    • <script> tag 사용
// 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 ...
}

toolkit button 추가하기

  • <vscode-button>
    • toolkit이 제공하는 button UI
// 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
    );
  }
}
  • 생성자 update
// 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에 전송
    • main.js 실행을 위한 코드
// 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>
  `;
}

결과

profile
There's Only One Thing To Do: Learn All We Can

0개의 댓글