-
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 개발에 더 많은 도움이 될 것이다.
'vscode extension' 카테고리의 다른 글
vscode extension Webview에 react 적용하기 (1) (1) 2022.03.13 vscode extension 기존 코드 가져와 돌려보고 싶을 때 (0) 2022.03.06