이거 너무 반복되는 일 같은데?
개발자라면 누구나 보일러플레이트를 줄이고 DRY 원칙에 따라 코드를 작성하려고 노력합니다. 그러나 개발 전체 프로세스를 고려했을 때, 단순히 코드 작성뿐만 아니라 반복되는 다른 작업도 줄이는 것이 중요함을 깨닫습니다. 가장 대표적인 예로, 반복되는 Pull Request에 사용될 템플릿을 미리 만들어 반복을 방지할 수 있습니다.
오늘은 개발 과정에서 느낀 불편함을 해소하기 위해 확장 프로그램을 만든 경험과 그 과정에서 얻은 교훈을 간략하게 공유해 보고자 합니다.
프로젝트를 진행하면서 컴포넌트를 관리하기 위해 다음과 같이 모듈화된 구조를 사용하곤 합니다:
│── Button
│ ├── Button.tsx
│ ├── index.ts
│ └── Button.styles.ts
이 구조를 사용하면 최소 네 번의 폴더 또는 파일 생성이 필요하며, 파일명을 잘못 입력하는 실수가 발생할 경우 수고롭게 이름을 수정해야 했습니다. 이런 문제로 인해, 급하게 기능을 추가할 때 이상적인 폴더 구조가 제대로 지켜지지 않는 경우가 종종 있었습니다.
이러한 불편함을 해결하기 위해 Visual Studio Code 확장 프로그램을 만들기로 결정했습니다.
Visual Studio에서는 확장 프로그램의 생성을 아래와 같이 쉽게 안내합니다.
yo code
를 실행하면 다음과 같은 텍스트 기반 사용자 인터페이스(TUI) 창을 통해 설정할 수 있습니다.
이후 물어보는 몇 가지의 질문에 답하면 프로젝트가 성공적으로 만들어지게 됩니다.
프로젝트 생성 후, vsc-extension-quickstart.md
문서를 참조하면 프로젝트의 구성요소와 디버깅 방법을 충분히 이해할 수 있습니다.
확장프로그램의 기능은 extension.ts
에서 구현할 수 있습니다. 저는 다음과 같이 기능을 정의하고 개발했습니다.
1. 사용자가 파일이나 폴더에서 보조 클릭을 할 경우, 커맨드를 실행할 수 있는 메뉴가 보인다.
// package.json
"contributes": {
"commands": [
{
"command": "dryfs.helloWorld",
"title": "Hello World"
},
{
"command": "dryfs.makeMyFolder",
"title": "Make My Folder"
}
],
"menus": {
"explorer/context": [
{
"command": "dryfs.makeMyFolder",
"when": "explorerViewletVisible"
}
]
},
2. 메뉴를 클릭시 폴더명을 유저에게 입력받을 수 있는 창이 나온다.
// extension.ts
const folderName = await vscode.window.showInputBox({
prompt: "Enter the folder name",
});
3. 입력받은 폴더명에 따라 생성된 폴더 내에 ${입력된 값}.tsx, index.ts, styles.ts, 그리고 테스트 파일 *.test.tsx을 추가한다.
// extension.ts
const newFolderPath = path.join(folderPath, folderName);
if (!fs.existsSync(newFolderPath)) {
fs.mkdirSync(newFolderPath);
}
const componentTemplate = isIncludeReactImport
? generateImportReactComponentTemplate(folderName)
: generateComponentTemplate(folderName);
const indexTemplate = generateIndexTemplate(folderName);
fs.writeFileSync(
path.join(newFolderPath, `${folderName}.tsx`),
componentTemplate
);
fs.writeFileSync(path.join(newFolderPath, "index.ts"), indexTemplate);
fs.writeFileSync(path.join(newFolderPath, "styles.ts"), "");
fs.writeFileSync(path.join(newFolderPath, `${folderName}.test.tsx`), "");
4. 생성완료 후 메시지가 보여진다.
vscode.window.showInformationMessage(
"Folder and files created successfully!"
);
이후, 트러블 슈팅 과정을 통해 폴더에서 보조클릭 했을 경우, 파일에서 보조클릭을 클릭 했을 경우등에 대한 디테일을 추가하며 확장프로그램의 구현을 마쳤습니다.
먼저, vsce package
명령어로 확장 프로그램을 빌드합니다. 이 명령어 실행 후, 프로젝트 내에 [확장 프로그램][버전].vsix 파일이 생성됩니다.
준비된 .visx
파일로 확장프로그램을 사용하는 방법은 크게 두 가지로 나뉘어 집니다.
VSCode의 확장 프로그램 탭(command+shift+x
)에서 install from VSIX...
를 선택하여 .vsix
파일을 설치합니다.
여기에서 Publisher 등록을 합니다.
등록된 Publisher 페이지에서 .vsix
파일을 업로드하여 출시할 수 있게 됩니다. 단, package.json
에 publisher
정보가 포함되어 있어야 합니다.
{
"name": "dryfs",
"publisher": "dryfs",
...
}
이후, 등록한 이메일을 통해 정상적으로 출시되었다는 안내를 받은 이후부터 다음과 같이 확장프로그램을 다운로드 받아 사용할 수 있습니다.
이 확장 프로그램을 개발함으로써 반복적인 클릭을 통해 폴더 구조를 만드는 번거로움을 한 번의 클릭으로 간소화할 수 있게 되었습니다. 또한, 개발 과정에서 다음과 같은 중요한 경험도 하게 되었습니다:
시멘틱 버저닝으로 라이브러리를 관리하는 경험:
시멘틱 버저닝의 개념은 익숙했지만, 확장 프로그램 개발을 통해 버전 관리의 실질적 중요성을 깊이 느꼈습니다. 이 경험은 향후 업데이트의 타이밍과 범위를 효과적으로 결정하는 데 크게 도움이 될 것입니다.
시멘틱 버저닝을 git tags
로 관리하는 경험:
git tags
를 통한 버저닝 관리는 프로젝트의 각 버전을 명확히 식별하고 이력을 추적할 수 있게 해주었습니다. 이는 확장 프로그램의 버전 관리를 용이하게 하며, 앞으로 다른 프로젝트에서도 유용하게 사용할 수 있을 것 같습니다.
’git tags’로 GitHub에서 릴리스를 출시하는 경험:
GitHub에서 직접 릴리스를 생성하면서, 각 릴리스에 자세한 설명과 문서를 첨부하는 것의 중요성을 깨달았습니다. 이는 다른 라이브러리의 릴리스 내용을 더욱 효과적으로 이해하고 파악할 수 있게 되었습니다.
앞으로 확장 프로그램을 고도화하면서 다음과 같은 부분에 기대를 하고 있습니다:
이 확장 프로그램이 문제를 겪고 계신 분들에게 도움이 되기를 바라며, 같은 수고스러움을 느껴보셨다면 한 번쯤 사용해 보셨으면 좋겠습니다. 그리고, 사용 중 개선할 점이 보인다면 GitHub를 통해 이슈를 등록해 주시거나 PR을 만들어 주심으로써 여러분과 협업할 기회를 얻을 수 있다면 더할 나위 없이 좋을 것 같습니다.
마지막으로, 확장 프로그램 개발이 생각보다 간단할 수 있다는 것을 알려드리고 싶습니다. 저 역시 처음 접하는 분야였지만, GPT와 같은 AI 도구를 활용하여 신속하게 MVP를 개발할 수 있었습니다. 여러분도 직접 확장 프로그램을 만들어보시면 개발 중 겪었던 불편함을 해결하고 새로운 경험을 얻을 수 있을 것입니다.
감사합니다.
https://code.visualstudio.com/api/get-started/your-first-extension
https://github.com/BO-LIKE-CHICKEN/do-not-repeat-your-folder-structure
vs 확장 프로그램 심사가 앱심사와 비교했을 때 훨씬 널널한 느낌이군요! npm 으로 오픈소스를 런칭하는 것도 또다른 묘미가 있었을 것 같네요. 재밌게 읽었습니다 :)