컴포넌트 하나를 만들기 위해서 폴더 하나에 컴포넌트 파일 하나와 스타일링 파일 하나를 각각 담는 경우가 많다. 파일마다 보일러 플레이트도 존재하기 때문에 컴포넌트의 개수가 많아질수록 매번 수동으로 다 만들기에 번거로움을 느껴 효율적인 작업을 하기 위해 익스텐션을 만들어봐야겠다는 생각을 하게 되었다.
💪🏻 만들고 싶은 익스텐션
여러 스타일링 도구에 적합한 익스텐션을 만들고 싶었기 때문에 구분이 필요했다. 일단은 내가 사용해본 styled componenet와 scss 대상으로 만들었다. 추후 더 추가할 예정!
생각한 동작은 아래와 같다.
1. 원하는 컴포넌트 위치의 상위 폴더에 우클릭을 한다.
2. "{컴포넌트명} {스타일링도구}" 을 입력받는다.
3. 컴포넌트명의 폴더가 생기고 하위에 컴포넌트 파일과 스타일링 파일이 자동 생성된다.
📌 기본 개념
우선 익스텐션에 대한 기본 개념부터 알고가야한다. 공식문서를 기반으로 작성하였다.
✅ Activation Events
어떤 상황이 발생할 때 이벤트를 활성화할 지 정의한다.
🚩 예시 ( 전체 이벤트 목록에 대한 공식문서는 여기에 )
onLanguage : 특정 언어로 해석되는 파일이 열렸을 때
"activationEvents": [
"onLanguage:python" //파이썬 파일이 열렸을 때 이벤트 발생
]
onCommand : 명령이 호출될 때
"activationEvents": [
"onCommand:extension.sayHello"
]
✅ Contribution Points
다양한 VSCode 구성요소와 기능 중 어떤 것들을 확장할 것인가에 대한 내용을 package.json에 JSON형태로 정의한다.
🚩 예시 ( 전체 contrubution points에 대한 공식문서는 여기에 )
views
: 좌측 사이드 바의 explorer(폴더 탐색기), scm(소스 관리), debug(실행 및 디버깅) 등의 뷰가 해당된다. 뷰의 식별자, 이름, 발생시점 등을 정의하여 뷰 내부에 다른 뷰를 추가할 수 있다.

아래의 코드는 explorer 뷰 내부에 node 의존성 라이브러리 목록을 볼 수 있는 트리 뷰를 추가하는 예시 내용이다.
{
"contributes": {
"views": {
"explorer": [
{
"id": "nodeDependencies",
"name": "Node Dependencies",
"when": "workspaceHasPackageJSON",
"icon": "media/dep.svg",
"contextualTitle": "Package Explorer"
}
]
}
}
}
commands: 명령에 대한 UI요소를 정의할 수 있다.
// 명령이 화면에 "Hello World"라고 보여진다.
{
"contributes": {
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World"
}
]
}
}
✅ VSCodeAPI
익스텐션 개발 코드에서 호출할 수 있는 JavaScript API 모음이다.
command, env, workspace 등 VS Code의 UI 구성요소와 환경 변수에 접근할 수 있는 네임스페이스와 인터페이스, 이벤트 핸들러 메소드 등 거의 필요한 모든 정보들이 정의되어 있다.
🚩 예시
command
: 명령을 처리하기 위한 네임스페이스로 고유식별자를 가진 함수를 다룬다. 이 네임스페이스를 통해 함수를 등록하면 앞서 정의한 contribution points에 의해 해당 함수를 실행시킬 수 있다.
//command API를 사용하여 extension.sayHello 명령에 함수를 등록한다.
commands.registerCommand('extension.sayHello', () => {
window.showInformationMessage('Hello World!');
});
이제 이 요소들을 사용하여 원하는 익스텐션을 만들 수 있다. 해보잣
🏃🏻♂️ 개발 과정
✨ 기본 세팅
공식문서를 기반으로 만들기 시작하였다.
$ npx --package yo --package generator-code -- yo code
기본 세팅은 이렇게 하였다. webpack을 사용해보고 싶었기에 웹팩을 통한 번들링에 동의했다.
# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? ComPoMaker
### Press <Enter> to choose default for all options below ###
# ? What's the identifier of your extension? compomaker
# ? What's the description of your extension?
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? Yes
# ? Which package manager to use? npm
# ? Do you want to open the new folder with Visual Studio Code? Open with `code`
✨ webpack 설정
webpack으로 번들링 작업을 거치기 위해 설정이 필요하다.
이 내용에 대해서는 별도의 블로그 포스팅으로 담아두었다!
✨ package.json 수정
이제 package.json을 수정해보자. package.json의 contributes 내부에서 명령에 대한 정보와 어떻게 명령에 대한 이벤트를 실행할 수 있는 지 설정 가능하다.
"contributes": {
"commands": [
{
"command": "makeComponent",
"title": "Make Component"
}
],
"menus": {
"explorer/context": [
{
"command": "makeComponent",
"group": "navigation", // 메뉴 최상단에 위치
"when": "explorerResourceIsFolder" // 폴더일 경우에만 명령이 활성화됨
}
]
}
}
commands에서 명령의 titile을 "Make Component"라고 설정하였고, menus에서 어디에 명령이 위치할 지를 설정하였다.
한마디로 설명하자면 explorer뷰에서 폴더일 경우에만 "Make Component"라는 명령이 context 메뉴에서 navigation에 위치하게 하였다.

✨ extension.ts 수정
명령을 실행하면 어떤 이벤트가 발생하는 지를 수정할 수 있다.
간단한 구분을 위해 styled component -> st / scss -> sc라고 입력받을 수 있게 하고, 스타일링 도구에 따라 파일과 내부 보일러 플레이트를 달리 하였다.
st -> {컴포넌트명}.styled.ts
sc -> {컴포넌트명}.module.scss
import * as vscode from "vscode";
import * as fs from "fs";
import * as path from "path";
import { mainTemplate } from "./template/main";
import { styleTemplate } from "./template/style";
export function activate(context: vscode.ExtensionContext) {
const commandFunc = async (uri: any) => {
const fp = uri.fsPath;
const component = await vscode.window.showInputBox({
placeHolder: "입력형식->컴포넌트명 스타일링도구(st/sc)",
validateInput: (str: string) => {
if (!str) {
return "컴포넌트명이 입력되지 않았습니다";
}
return undefined;
},
});
const getStylingFile = (name: string, type: string) => {
if (type == "st") return `${name}.styled.ts`;
if (type == "sc") return `${name}.module.scss`;
return "";
};
if (component) {
const [componentName, componentStyle] = component?.split(" ");
const componentPath = path.join(fp, componentName);
const stylingFile = getStylingFile(componentName, componentStyle);
if (fs.existsSync(componentPath)) {
vscode.window.showInformationMessage(
"컴포넌트 폴더 생성에 실패하였습니다."
);
} else if (componentStyle != "st" && componentStyle != "sc") {
vscode.window.showInformationMessage(
"올바르지 않은 스타일링 도구입니다."
);
} else {
fs.mkdirSync(componentPath);
const indexFilePath = path.join(componentPath, `${componentName}.tsx`);
const styleFilePath = path.join(componentPath, `${stylingFile}`);
fs.writeFileSync(
indexFilePath,
mainTemplate(componentName, stylingFile)
);
fs.writeFileSync(styleFilePath, styleTemplate(componentStyle));
vscode.window.showInformationMessage("컴포넌트 폴더가 생성되었습니다.");
}
}
};
let disposable = vscode.commands.registerCommand("makeComponent", (uri) => {
commandFunc(uri);
});
context.subscriptions.push(disposable);
}
export function deactivate() {}
파일의 정확한 경로와 파일 처리를 위해 path모듈과 fs모듈을 가져와 사용하고, if 문으로 나름의 에러 처리(?)를 하였다.
✨ 디버깅
이제 다 만든 익스텐션을 실행시켜보자! VSCode의 디버그 모드를 통해 익스텐션을 실행시켜볼 수 있다.
이것은 좀 TMI이지만..
매번 vscode에서 코드를 실행할 때 전체 실행(run)만 해봤지 디버그(debug)는 처음 시도해보았다. 뭐가 다른가 싶었는데 디버그 모드로 실행할 경우에는 중단점을 설정할 수 있다고 한다.
실제로 중단점을 설정하여 실행 테스트를 해보니 중단점 코드의 실행 전과 실행 후의 상태를 바로 확인할 수 있어서 console로 로그를 찍는 것보다 어디서 에러가 발생했는 지 명확하게 알 수 있어서 좋았다.!
1. 폴더의 좌클릭을 하여 메뉴에서 명령을 누르면

2. "{컴포넌트명} {스타일링도구}"을 입력하고

3. 폴더와 하위 파일들이 생성된다!

🎁 패키징과 배포
배포를 해보자!
일단 익스텐션을 패키징하여 하나의 파일로 압축하기 위해 VSCode extension manager 를 설치한다.
npm install -g vsce
그리고 리드미를 수정한다. 왜인지는 모르겠지만 리드미 첫 수정을 하지 않으면 파일 업로드시 에러가 난다.
그리고 마켓플레이스 사이트에서 Publish Extension을 눌러 publiserId를 생성한다. 이렇게 생성한 publiserId와 리드미에 관한 설정을 패키징 전에 package.json에 추가해주어야 한다.
//package.json
"readme": "./README.md",
"publisher": {생성한 publiser id}
이제 패키징 한다.
vsce package
패키징을 완료하면 .vsix 확장자 파일이 하나 만들어진다.
이제 이 파일을 마켓플레이스에서 생성한 publisher의 파일로 등록하면 배포가 완료된다! ( 10~15분의 시간 소요 )

🎆 후기

VSCode의 익스텐션을 만들어보다니 신기했다.ㅎㅎ 간단하지만 개발의 효율성을 높일 방법을 만들었다는 것에 대하여 꽤 뿌듯함을 느꼈다. extension에 다양한 설정 기능이 있던데, 개발 규모가 큰 프로젝트에 참여하게 될 경우 이번 경험을 토대로 더 좋은 익스텐션을 만들어 협업 과정의 도움을 줄 수 있을 것 같단 생각을 하게 되었다.
참고
https://code.visualstudio.com/api/get-started/your-first-extension
'회고' 카테고리의 다른 글
[회고] 오롯이 혼자서 커뮤니티 만들어 본 후기 (0) | 2023.12.05 |
---|---|
[회고] 원티드 프리온보딩 인턴십 회고(라 쓰고 느낀 점이라 읽는다) (0) | 2023.07.27 |
[회고] 유튜브 댓글 분석 서비스 프로젝트 후기 (0) | 2023.04.15 |
컴포넌트 하나를 만들기 위해서 폴더 하나에 컴포넌트 파일 하나와 스타일링 파일 하나를 각각 담는 경우가 많다. 파일마다 보일러 플레이트도 존재하기 때문에 컴포넌트의 개수가 많아질수록 매번 수동으로 다 만들기에 번거로움을 느껴 효율적인 작업을 하기 위해 익스텐션을 만들어봐야겠다는 생각을 하게 되었다.
💪🏻 만들고 싶은 익스텐션
여러 스타일링 도구에 적합한 익스텐션을 만들고 싶었기 때문에 구분이 필요했다. 일단은 내가 사용해본 styled componenet와 scss 대상으로 만들었다. 추후 더 추가할 예정!
생각한 동작은 아래와 같다.
1. 원하는 컴포넌트 위치의 상위 폴더에 우클릭을 한다.
2. "{컴포넌트명} {스타일링도구}" 을 입력받는다.
3. 컴포넌트명의 폴더가 생기고 하위에 컴포넌트 파일과 스타일링 파일이 자동 생성된다.
📌 기본 개념
우선 익스텐션에 대한 기본 개념부터 알고가야한다. 공식문서를 기반으로 작성하였다.
✅ Activation Events
어떤 상황이 발생할 때 이벤트를 활성화할 지 정의한다.
🚩 예시 ( 전체 이벤트 목록에 대한 공식문서는 여기에 )
onLanguage : 특정 언어로 해석되는 파일이 열렸을 때
"activationEvents": [
"onLanguage:python" //파이썬 파일이 열렸을 때 이벤트 발생
]
onCommand : 명령이 호출될 때
"activationEvents": [
"onCommand:extension.sayHello"
]
✅ Contribution Points
다양한 VSCode 구성요소와 기능 중 어떤 것들을 확장할 것인가에 대한 내용을 package.json에 JSON형태로 정의한다.
🚩 예시 ( 전체 contrubution points에 대한 공식문서는 여기에 )
views
: 좌측 사이드 바의 explorer(폴더 탐색기), scm(소스 관리), debug(실행 및 디버깅) 등의 뷰가 해당된다. 뷰의 식별자, 이름, 발생시점 등을 정의하여 뷰 내부에 다른 뷰를 추가할 수 있다.

아래의 코드는 explorer 뷰 내부에 node 의존성 라이브러리 목록을 볼 수 있는 트리 뷰를 추가하는 예시 내용이다.
{
"contributes": {
"views": {
"explorer": [
{
"id": "nodeDependencies",
"name": "Node Dependencies",
"when": "workspaceHasPackageJSON",
"icon": "media/dep.svg",
"contextualTitle": "Package Explorer"
}
]
}
}
}
commands: 명령에 대한 UI요소를 정의할 수 있다.
// 명령이 화면에 "Hello World"라고 보여진다.
{
"contributes": {
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World"
}
]
}
}
✅ VSCodeAPI
익스텐션 개발 코드에서 호출할 수 있는 JavaScript API 모음이다.
command, env, workspace 등 VS Code의 UI 구성요소와 환경 변수에 접근할 수 있는 네임스페이스와 인터페이스, 이벤트 핸들러 메소드 등 거의 필요한 모든 정보들이 정의되어 있다.
🚩 예시
command
: 명령을 처리하기 위한 네임스페이스로 고유식별자를 가진 함수를 다룬다. 이 네임스페이스를 통해 함수를 등록하면 앞서 정의한 contribution points에 의해 해당 함수를 실행시킬 수 있다.
//command API를 사용하여 extension.sayHello 명령에 함수를 등록한다.
commands.registerCommand('extension.sayHello', () => {
window.showInformationMessage('Hello World!');
});
이제 이 요소들을 사용하여 원하는 익스텐션을 만들 수 있다. 해보잣
🏃🏻♂️ 개발 과정
✨ 기본 세팅
공식문서를 기반으로 만들기 시작하였다.
$ npx --package yo --package generator-code -- yo code
기본 세팅은 이렇게 하였다. webpack을 사용해보고 싶었기에 웹팩을 통한 번들링에 동의했다.
# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? ComPoMaker
### Press <Enter> to choose default for all options below ###
# ? What's the identifier of your extension? compomaker
# ? What's the description of your extension?
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? Yes
# ? Which package manager to use? npm
# ? Do you want to open the new folder with Visual Studio Code? Open with `code`
✨ webpack 설정
webpack으로 번들링 작업을 거치기 위해 설정이 필요하다.
이 내용에 대해서는 별도의 블로그 포스팅으로 담아두었다!
✨ package.json 수정
이제 package.json을 수정해보자. package.json의 contributes 내부에서 명령에 대한 정보와 어떻게 명령에 대한 이벤트를 실행할 수 있는 지 설정 가능하다.
"contributes": {
"commands": [
{
"command": "makeComponent",
"title": "Make Component"
}
],
"menus": {
"explorer/context": [
{
"command": "makeComponent",
"group": "navigation", // 메뉴 최상단에 위치
"when": "explorerResourceIsFolder" // 폴더일 경우에만 명령이 활성화됨
}
]
}
}
commands에서 명령의 titile을 "Make Component"라고 설정하였고, menus에서 어디에 명령이 위치할 지를 설정하였다.
한마디로 설명하자면 explorer뷰에서 폴더일 경우에만 "Make Component"라는 명령이 context 메뉴에서 navigation에 위치하게 하였다.

✨ extension.ts 수정
명령을 실행하면 어떤 이벤트가 발생하는 지를 수정할 수 있다.
간단한 구분을 위해 styled component -> st / scss -> sc라고 입력받을 수 있게 하고, 스타일링 도구에 따라 파일과 내부 보일러 플레이트를 달리 하였다.
st -> {컴포넌트명}.styled.ts
sc -> {컴포넌트명}.module.scss
import * as vscode from "vscode";
import * as fs from "fs";
import * as path from "path";
import { mainTemplate } from "./template/main";
import { styleTemplate } from "./template/style";
export function activate(context: vscode.ExtensionContext) {
const commandFunc = async (uri: any) => {
const fp = uri.fsPath;
const component = await vscode.window.showInputBox({
placeHolder: "입력형식->컴포넌트명 스타일링도구(st/sc)",
validateInput: (str: string) => {
if (!str) {
return "컴포넌트명이 입력되지 않았습니다";
}
return undefined;
},
});
const getStylingFile = (name: string, type: string) => {
if (type == "st") return `${name}.styled.ts`;
if (type == "sc") return `${name}.module.scss`;
return "";
};
if (component) {
const [componentName, componentStyle] = component?.split(" ");
const componentPath = path.join(fp, componentName);
const stylingFile = getStylingFile(componentName, componentStyle);
if (fs.existsSync(componentPath)) {
vscode.window.showInformationMessage(
"컴포넌트 폴더 생성에 실패하였습니다."
);
} else if (componentStyle != "st" && componentStyle != "sc") {
vscode.window.showInformationMessage(
"올바르지 않은 스타일링 도구입니다."
);
} else {
fs.mkdirSync(componentPath);
const indexFilePath = path.join(componentPath, `${componentName}.tsx`);
const styleFilePath = path.join(componentPath, `${stylingFile}`);
fs.writeFileSync(
indexFilePath,
mainTemplate(componentName, stylingFile)
);
fs.writeFileSync(styleFilePath, styleTemplate(componentStyle));
vscode.window.showInformationMessage("컴포넌트 폴더가 생성되었습니다.");
}
}
};
let disposable = vscode.commands.registerCommand("makeComponent", (uri) => {
commandFunc(uri);
});
context.subscriptions.push(disposable);
}
export function deactivate() {}
파일의 정확한 경로와 파일 처리를 위해 path모듈과 fs모듈을 가져와 사용하고, if 문으로 나름의 에러 처리(?)를 하였다.
✨ 디버깅
이제 다 만든 익스텐션을 실행시켜보자! VSCode의 디버그 모드를 통해 익스텐션을 실행시켜볼 수 있다.
이것은 좀 TMI이지만..
매번 vscode에서 코드를 실행할 때 전체 실행(run)만 해봤지 디버그(debug)는 처음 시도해보았다. 뭐가 다른가 싶었는데 디버그 모드로 실행할 경우에는 중단점을 설정할 수 있다고 한다.
실제로 중단점을 설정하여 실행 테스트를 해보니 중단점 코드의 실행 전과 실행 후의 상태를 바로 확인할 수 있어서 console로 로그를 찍는 것보다 어디서 에러가 발생했는 지 명확하게 알 수 있어서 좋았다.!
1. 폴더의 좌클릭을 하여 메뉴에서 명령을 누르면

2. "{컴포넌트명} {스타일링도구}"을 입력하고

3. 폴더와 하위 파일들이 생성된다!

🎁 패키징과 배포
배포를 해보자!
일단 익스텐션을 패키징하여 하나의 파일로 압축하기 위해 VSCode extension manager 를 설치한다.
npm install -g vsce
그리고 리드미를 수정한다. 왜인지는 모르겠지만 리드미 첫 수정을 하지 않으면 파일 업로드시 에러가 난다.
그리고 마켓플레이스 사이트에서 Publish Extension을 눌러 publiserId를 생성한다. 이렇게 생성한 publiserId와 리드미에 관한 설정을 패키징 전에 package.json에 추가해주어야 한다.
//package.json
"readme": "./README.md",
"publisher": {생성한 publiser id}
이제 패키징 한다.
vsce package
패키징을 완료하면 .vsix 확장자 파일이 하나 만들어진다.
이제 이 파일을 마켓플레이스에서 생성한 publisher의 파일로 등록하면 배포가 완료된다! ( 10~15분의 시간 소요 )

🎆 후기

VSCode의 익스텐션을 만들어보다니 신기했다.ㅎㅎ 간단하지만 개발의 효율성을 높일 방법을 만들었다는 것에 대하여 꽤 뿌듯함을 느꼈다. extension에 다양한 설정 기능이 있던데, 개발 규모가 큰 프로젝트에 참여하게 될 경우 이번 경험을 토대로 더 좋은 익스텐션을 만들어 협업 과정의 도움을 줄 수 있을 것 같단 생각을 하게 되었다.
참고
https://code.visualstudio.com/api/get-started/your-first-extension
'회고' 카테고리의 다른 글
[회고] 오롯이 혼자서 커뮤니티 만들어 본 후기 (0) | 2023.12.05 |
---|---|
[회고] 원티드 프리온보딩 인턴십 회고(라 쓰고 느낀 점이라 읽는다) (0) | 2023.07.27 |
[회고] 유튜브 댓글 분석 서비스 프로젝트 후기 (0) | 2023.04.15 |