본문 바로가기

카테고리 없음

VSCode 확장 프로그램 만들기 (1) - 확장 프로그램 시작하기

VSCode 확장 프로그램 개발 시작하기

VSCode는 개발자들에게 가장 사랑받는 에디터 중 하나다. 그 이유 중 하나는 바로 확장 프로그램(Extension) 생태계 덕분이다. 이번 글에서는 VSCode 확장 프로그램을 만드는 방법과 개발 과정에서 겪은 경험을 공유한다.

 

개발 환경 구축

VSCode 확장 프로그램을 만들기 위해서는 먼저 개발 환경을 구축해야 한다. Yeoman과 generator-code를 사용하면 확장 프로그램의 기본 템플릿을 쉽게 생성할 수 있다.

npm install -g yo generator-code

yo code

 

템플릿 생성 시 여러 옵션을 선택할 수 있는데, 나는 TypeScript와 esbuild를 선택했다. Webpack 대신 esbuild를 선택한 이유는 빌드 속도가 월등히 빠르기 때문이다.

 

프로젝트 구조

생성된 프로젝트의 핵심 파일 구조는 다음과 같다.

style-rank/
├── src/
│   └── extension.ts       # 확장 프로그램 진입점
├── package.json           # 확장 프로그램 설정 및 메타데이터
├── tsconfig.json          # TypeScript 설정
└── esbuild.js            # 빌드 설정

 

package.json 설정

package.json은 확장 프로그램의 메타데이터를 정의하는 핵심 파일이다.

{
  "name": "style-rank",
  "displayName": "Style Rank",
  "description": "AST 기반 코드 품질 랭크 측정기",
  "version": "0.0.4",
  "icon": "extension-icon.png",
  "engines": {
    "vscode": "^1.105.0"
  },
  "activationEvents": [
    "onLanguage:javascript",
    "onLanguage:typescript",
    "onLanguage:javascriptreact",
    "onLanguage:typescriptreact"
  ],
  "main": "./dist/extension.js",
  "contributes": {
    "commands": [
      {
        "command": "style-rank.helloWorld",
        "title": "Hello World"
      }
    ]
  }
}

 

activationEvents는 확장 프로그램이 언제 활성화될지를 정의한다. 여기서는 JavaScript와 TypeScript 파일이 열릴 때 자동으로 활성화되도록 설정했다. icon은 추후 확장 프로그램으로 패키징 하였을 때 표시될 앱의 아이콘이다. 선택적으로 적용하면 된다.

 

 

extension.ts - 진입점 구현

'src/extension.ts'는 확장 프로그램의 진입점이다. VSCode는 activate 함수를 호출하여 확장 프로그램을 실행한다.

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  // 파일 저장 이벤트 리스너
  const saveListener = vscode.workspace.onDidSaveTextDocument((document) => {
    const supportedLanguages = ['typescript', 'javascript', 'typescriptreact', 'javascriptreact'];

    if (!supportedLanguages.includes(document.languageId)) {
      console.log('지원하지 않는 언어입니다.');
      return;
    }

    try {
      const code = document.getText();
      const fileName = path.basename(document.fileName);
      analyzeCode(code, fileName, document.fileName, true);
    } catch (e) {
      vscode.window.showErrorMessage(
        `코드 분석 중 오류가 발생했습니다: ${e instanceof Error ? e.message : String(e)}`
      );
    }
  });

  context.subscriptions.push(saveListener);
}

 

이 코드는 파일이 저장될 때마다 onDidSaveTextDocument 이벤트를 감지하여 코드 분석을 실행한다.

 

 

명령어(Command) 등록

VSCode 확장 프로그램은 명령어를 통해 사용자와 상호작용할 수 있다. 명령어는 Command Palette(Ctrl+Shift+P 윈도우)에서 실행할 수 있다.

const testCommand = vscode.commands.registerCommand(
  'style-rank.helloWorld',
  async () => {
    try {
      const sampleFilePath = path.join(
        context.extensionPath,
        'test-samples',
        'sample1.js'
      );

      const testCode = fs.readFileSync(sampleFilePath, 'utf-8');
      analyzeCode(testCode, 'sample1.js', sampleFilePath, true);
    } catch (e) {
      console.error('Error:', e);
      vscode.window.showErrorMessage(
        `분석 중 오류가 발생했습니다: ${e instanceof Error ? e.message : String(e)}`
      );
    }
  }
);

context.subscriptions.push(testCommand);

 

상태바(Status Bar) UI 구현

VSCode 하단의 상태바는 사용자에게 정보를 표시하는 효과적인 방법이다. 이번 프로젝트에서 코드의 품질을 검사하고 평가된 점수를 보여주기 위해서 가장 효과적인 방법을 고민했는데, 윈도우의 작업표시줄, 맥의 메뉴바의 위치에 고양이가 나타나는 RunCat 앱이 떠올라 VSCode IDE 하단에 상태바로 제공하기로 결정하였다.

 

src/statusBar.ts에서 상태바를 관리하는 클래스를 구현했다.

import * as vscode from 'vscode';
import type { Rank } from './ranking';

export class StatusBarManager {
  private statusBarItem: vscode.StatusBarItem;

  constructor(commandId: string) {
    this.statusBarItem = vscode.window.createStatusBarItem(
      vscode.StatusBarAlignment.Right,
      100
    );
    this.statusBarItem.command = commandId;
  }

  updateRank(rank: Rank, complexity: number, description: string): void {
    const icon = this.getRankIcon(rank);
    const color = this.getRankColor(rank);

    this.statusBarItem.text = `${icon} Rank: ${rank}`;
    this.statusBarItem.tooltip = `순환 복잡도: ${complexity}\\\\n${description}\\\\n\\\\n클릭하여 상세 보기`;
    this.statusBarItem.backgroundColor = color;
    this.statusBarItem.show();
  }

  private getRankIcon(rank: Rank): string {
    const icons: Record<Rank, string> = {
      S: '$(star-full)',
      A: '$(별)',
      B: '$(check)',
      C: '$(warning)',
      D: '$(alert)',
      F: '$(error)',
    };
    return icons[rank];
  }
}

 

VSCode는 `$(icon-name)` 형식으로 내장 아이콘을 제공한다. 이를 활용하면 시각적으로 풍부한 UI를 쉽게 구현할 수 있다. 초안은 이런식으로 상태바를 제공하고 호버 혹은 클릭 시 상세 정보를 보여주도록 구성하였다. 추후 이 방식은 QuickPick을 이용해 개선 파일 위치를 찾아주도록 개선된다.

 

 

디버깅 환경 설정

확장 프로그램 개발에서 가장 중요한 것은 빠른 피드백 사이클이다. VSCode는 F5 키 하나로 확장 프로그램을 테스트할 수 있는 Extension Development Host를 제공한다.

 

'.vscode/launch.json' 설정:

{
  "version": "0.0.1",
  "configurations": [
    {
      "name": "Run Extension",
      "type": "extensionHost",
      "request": "launch",
      "args": [
        "--extensionDevelopmentPath=${workspaceFolder}"
      ],
      "outFiles": [
        "${workspaceFolder}/dist/**/*.js"
      ],
      "preLaunchTask": "${defaultBuildTask}"
    }
  ]
}

 

이 설정을 통해 F5를 누르면 자동으로 빌드가 실행되고, 새로운 VSCode 창에서 확장 프로그램이 로드된다. 해당 창에서 명령팔레트를 통해 테스트 파일을 실행해보거나, 혹은 원하는 파일을 열어 사전에 설정된 커맨드를 통해 테스트를 해볼 수 있다.

 

 

빌드 및 배포

개발이 완료되면 확장 프로그램을 패키징하여 배포할 수 있다.

# 개발 빌드
npm run compile

# 프로덕션 빌드
npm run package

# VSIX 파일 생성
vsce package

 

vsce package 명령어는 .vsix 파일을 생성하는데, 이를 VSCode Marketplace에 배포하거나 직접 설치할 수 있다. 직접 설치하여 이상이 없는지 테스트를 마치면 VSCode Marketplace에 배포할 준비가 된 것이다.

 

Visual Studio Marketplace는 Microsoft의 Azure DevOps를 통해 관리된다. 마켓에 자신의 앱을 등록하기 위해서는 개인 액세스 토큰(PAT)을 발급 받아야한다.

vsce login <Publisher Name>

 

위 명령어를 통해 vsce에 로그인을 시도하면 PAT을 입력하라는 메시지가 노출된다. 여기에 발급받은 PAT 토큰을 사용하면 된다.

마지막으로 배포하고자 하는 프로젝트 루트로 이동하여

vsce publish

 

를 실행하면 확장 프로그램의 배포가 완료된다.

 

 

버전 관리

배포시에 코드를 올리는 것과 함께 중요하게 여겨야하는 것이 바로 버전이다. 사용자들은 코드를 확인하는 것이 아니라 해당 프로그램에 어떠한 변화가 있었는지 업데이트마다 쉽게 파악할 수 있는 수단이 필요하다. 이 수단으로 사용되는 것이 바로 버전이다.

 

여기서 사용되는 버전 관리 방식은 Semantic Versioning 규칙이다. 의미론적 버전 관리라는 의미인데, 이 관리 방식은 세 개의 숫자를 점(.)으로 구분하여 버전에 의미를 부여한다.

 

버전 형식: MAJOR.MINOR.PATCH (예시: 1.3.9)

  • MAJOR: 주 버전, 이전 버전과 호환성이 완전히 깨지는 대규모 변경이 존재할 때
  • MINOR: 부 버전, 이전 버전과 호환성이 깨지지 않고 새로운 기능이 추가되었을 때
  • PATCH: 수정 버전, 이전 버전과 호환성이 깨지지 않고 버그 수정이나 작은 개선이 존재할 때

이렇게 관리되는 버전은 수동으로 그 의미에 맞게 숫자를 증가시켜 적용하기도 하지만, vsce를 사용할 때에는 간단한 명령어를 통해 해결가능하다.

# package.json의 PATCH 버전을 자동으로 1 증가시키고 게시합니다.
vsce publish patch

 

이렇게 원하는 버전 변경 방식을 선택하여 버전 관리와 배포를 동시에 처리할 수도 있다.