ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • vscode Extension 개발 ( Canvas 적용해보기 + 테트리스 게임 적용 )
    vscode extension 2022. 3. 1. 00:08

    vscode Extension을 공부하던 도중 WebView라는 api를 공부하던 도중

    Canvas가 되는 지 궁금했다.  그래서 구글링 해보니 가능하다는 포스팅을 확인하였다.

     

    https://dev.to/coderallan/vscode-extension-using-webview-and-message-posting-5435

    맙소사, github으로 예제까지 제공해주었다.

    https://github.com/CoderAllan/vscode-extension-webview

    돌려본 결과 정상적으로 동작하는 것을 확인할 수 있었고,

    ( 개발환경만 기본 설치한 경우면, 

    1. import { Base64 } from 'js-base64'

    에서 에러가 날것이며, 해당 node module은 npm install js-base64를 통해서 모듈 설치 후 프로젝트 경로로 모듈을 옮겨오면 해결된다.

    2. 그리고 추가적으로 깃헙에서 받은건 .vscode 폴더가 없다. 다른 기본 vscode extension 프로젝트에서 복사해서 붙여넣으면 된다. )

     

    canvas가 webview 안에서 정상동작하면, 게임도 돌아갈거같은데? 라는 생각이 들어서, 

    깃헙에서 간단한 canvas 테트리스게임을 가져와서 포팅해봤다.

    https://github.com/dionyziz/canvas-tetris 

     

    메인 코드인 entension.ts 파일은 vscode-extension-webview 프로젝트에 있는 webview 부분을 테트리스 js 를 호출하도록 적용한 것뿐이다.

    import * as vscode from 'vscode';
    import { Base64 } from 'js-base64';
    import * as fs from 'fs';
    import * as path from 'path';
    
    export function activate(context: vscode.ExtensionContext) {
      const vscodeTestDisposable = vscode.commands.registerCommand('vscodetest.webview', () => {
        const webviewPanel = vscode.window.createWebviewPanel(
          'vscodeTest',
          'VsCode test webview',
          vscode.ViewColumn.One,
          {
            enableScripts: true
          }
        );    
        webviewPanel.webview.onDidReceiveMessage(
          message => {
            switch (message.command) {
              case 'saveAsPng':
                saveAsPng(message.text);
                return;
            }
          },
          undefined,
          context.subscriptions
        );
        //setHtmlContent(webviewPanel.webview, context); 요기를
        setHtmlContentTetris(webviewPanel.webview, context); // 요기로 바꿈
      });
      context.subscriptions.push(vscodeTestDisposable);
    }
    
    function getWorkspaceFolder(): string {
      var folder = vscode.workspace.workspaceFolders;
      var directoryPath: string = '';
      if (folder != null) {
        directoryPath = folder[0].uri.fsPath;
      }
      return directoryPath;
    }
    
    function writeFile(filename: string, content: string | Uint8Array, callback: () => void) {
      fs.writeFile(filename, content, function (err) {
        if (err) {
          return console.error(err);
        }
        callback();
      });
    }
    
    function saveAsPng(messageText: string) {
      const dataUrl = messageText.split(',');
      if (dataUrl.length > 0) {
        const u8arr = Base64.toUint8Array(dataUrl[1]);
    
        const workspaceDirectory = getWorkspaceFolder();
        const newFilePath = path.join(workspaceDirectory, 'VsCodeExtensionTest.png');
        writeFile(newFilePath, u8arr, () => {
          vscode.window.showInformationMessage(`The file ${newFilePath} has been created in the root of the workspace.`);      
        });
      }
    }
    
    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;
    }
    // 이걸 씀 테트리스 js 적용 코드, 대충 돌아만 가게 짬 (연결한 수준)
    function setHtmlContentTetris(webview: vscode.Webview, extensionContext: vscode.ExtensionContext) 
    {
      const tetrisPath = vscode.Uri.joinPath(extensionContext.extensionUri, 'javascript', 'tetris.js');
      const controllerPath = vscode.Uri.joinPath(extensionContext.extensionUri, 'javascript', 'controller.js');
      const renderPath = vscode.Uri.joinPath(extensionContext.extensionUri, 'javascript', 'render.js');
      const tetrisUri =(tetrisPath).with({ 'scheme': 'vscode-resource' });
      const controllerUri = (controllerPath).with({ 'scheme': 'vscode-resource' });
      const renderUri = (renderPath).with({ 'scheme': 'vscode-resource' });
    
    
      let htmlContent = `<!DOCTYPE html>
      <html>
          <head>
              <title>HTML5 Tetris</title>
              <link rel='stylesheet' href='style.css' />
          </head>
          <body>
              <audio id="clearsound" src="sound/pop.ogg" preload="auto"></audio>
              <canvas width='300' height='600'></canvas>
              <button id="playbutton" onclick="playButtonClicked();">Play</button>
              <script src="${tetrisUri}"></script>
              <script src="${controllerUri}"></script>
              <script src="${renderUri}"></script>
          </body>
      </html>`;
    
      webview.html = htmlContent;
    }
    
    // 이건 안씀
    function setHtmlContent(webview: vscode.Webview, extensionContext: vscode.ExtensionContext) {
      let htmlContent = `<html>
      <head>
        <meta charset="UTF-8">
        <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src cspSource; script-src 'nonce-nonce';">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href="vscodeTest.css" rel="stylesheet">
      </head>
      <body>
        <div id="buttons">
          <input type="button" id="saveAsPngButton" value="Save as png">
        </div>
        <div id="canvasSection"><canvas id="vscodeTestCanvas" /></div>
        <script type="text/javascript" src="vscodeTest.js"></script>
      </body>
    </html>`;
      const jsFilePath = vscode.Uri.joinPath(extensionContext.extensionUri, 'javascript', 'vscodeTest.js');
      const visUri = webview.asWebviewUri(jsFilePath);
      htmlContent = htmlContent.replace('vscodeTest.js', visUri.toString());
    
      const cssPath = vscode.Uri.joinPath(extensionContext.extensionUri, 'stylesheet', 'vscodeTest.css');
      const cssUri = webview.asWebviewUri(cssPath);
      htmlContent = htmlContent.replace('vscodeTest.css', cssUri.toString());
      
      const nonce = getNonce();
      htmlContent = htmlContent.replace('nonce-nonce', `nonce-${nonce}`);
      htmlContent = htmlContent.replace(/<script /g, `<script nonce="${nonce}" `);
      htmlContent = htmlContent.replace('cspSource', webview.cspSource);
      
      webview.html = htmlContent;
    }
    
    // this method is called when your extension is deactivated
    export function deactivate() { }

    폴더 구조

    왼쪽 그림은 내가 수정한 폴더 구조이다. 원래 javascript 폴더에 vscodeTest.js 파일만 있었는데 테트리스 코드들을 다 해당 폴더안에 집어넣었다. controller.js, render.js tetris.js

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    그리고  running 후 새로 뜬 vscode 프로젝트 창에서

    CTRL + SHIFT + P 누르면 설정 탭이 뜨고

    거기서 VsCode test webview 를 검색해서 수행해보았더니

     

     

    테트리스 게임이 되네?당연한 이야기지만 canvas가 된다면 canvas 로 만든 게임도 된다는 거다.

    canvas의 유용한 기능을 적용하면 vscode Extension 개발에 더 많은 도움이 될 것이다.

     

Designed by Tistory.