티스토리 뷰
안녕하세요. 오늘은 제가 현재 회사에서 프론트엔드 팀의 보일러플레이트 관리를 위해 모노레포를 도입한 경험을 공유하고자 합니다.
틈새 어필 [updated 24.09.02] 관련하여 적은 글이 회사 공식 블로그에도 기술되어있습니다. 시스템 팀의 본질적인 고민과, 방향성을 담은 부분도 있으니 궁금하신 분들은 찾아봐주세요! 똑똑한개발자 프론트엔드 시스템팀은 이렇게 일해요.
올해 시스템 업무를 맡게 되면서, 가장 먼저 계획했던 일이 바로 보일러플레이트의 모노레포화를 추진하는 것이었습니다. 회사의 보일러플레이트는 초기 프로젝트 세팅에 필요한 코드나 공통 컴포넌트, 유틸리티, 훅 등을 모아두는 역할을 합니다. 시간이 지나며 보일러플레이트는 점점 더 발전하고 기능이 추가되면서, 이를 역할별로 분리하여 버전 관리할 필요성이 커졌습니다.
특히 Next.js 13 버전부터는 앱 라우터(App Router)와 페이지 라우터(Page Router) 방식이 나뉘게 되었는데요, 이로 인해 두 가지 라우터 방식을 모두 지원하는 보일러플레이트가 필요해졌습니다. 이 외에도 다양한 이유로 인해 모노레포 적용이 꼭 필요한 작업이라는 판단이 섰습니다.
처음으로 모노레포 작업에 도전하면서 여러 도구들을 시도해보았고, 예상치 못한 이슈들도 많이 겪었는데요, 오늘은 모노레포를 적용하게 된 이유와 그 과정에서 사용한 패키지 리스트, 그리고 개발 툴들에 대해 소개해드리겠습니다. 이 글을 바탕으로, 이후 포스팅에서는 사용한 개발 툴에 대해 좀 더 자세하게 다뤄보겠습니다.
모노레포 적용 왜 했나요?
보일러플레이트를 모노레포 구조로 이관하게 된 이유는 다음과 같습니다:
- 공통 컴포넌트, 유틸, 훅의 라이브러리화
- 필요한 기능만 선택적으로 import하여 사용하는 방식으로 빌드의 경량화를 달성하고, 모듈 분리를 통해 사용성을 개선하고자 했습니다.
- Next.js의 앱 라우터와 페이지 라우터를 개별 템플릿으로 관리
- CLI를 통해 애플리케이션을 생성하고, 모노레포 안에서 이 템플릿들을 관리합니다. 명령어로 라우터 방식, React Query 버전 등을 선택하여 로컬 경로에 애플리케이션을 설치할 수 있습니다.
- 이를 통해, 매번 GitHub에서 템플릿을 생성해야 하는 번거로움이 사라졌습니다.
- CLI 및 모듈화
- gen img, gen icon, gen api, gen webp와 같은 CLI 명령어와, hooks, utils, components를 개별 모듈로 분리했습니다.
- 이렇게 모듈화를 통해 실무자들의 기여도를 높이고, 사용하지 않는 모듈은 배포에서 제외하여 빌드 사이즈를 줄였습니다.
- 또한, 의존성 있는 라이브러리의 변경이 발생해도, 각 모듈이 독립적으로 버전 관리되기 때문에 유지보수와 이슈 대응이 편리해졌습니다.
- CI/CD
- 각 모듈의 버전을 관리하며, 패키지가 배포될 때마다 changelog와 releasenote를 자동으로 생성하도록 설정했습니다.
어떻게 되기를 기대하나요?
- 관리상 편함과 history 추적을 수월하게 하고 싶습니다.
- hooks utils 등을 모듈화 시켜, 모든 경우에 대응하지 않는 모듈도 포함하여 기존 실무자분들의 기여도를 높이고 싶습니다.
- 프로젝트 클론, 배포까지의 과정을 CLI로 자동화하여 작업 효율을 높히고 싶습니다.
Npm Package List
Scope : toktokhan-dev
- tokit
- 프런트 init 템플릿을 생성해주는 cli 툴입니다. 변동사항이 큰 패키지를 대비해 버전별로 설치할 수 있는 옵션이 제공됩니다.
- Next Page/App Router
- cli
사내 프론트 개발 업무를 도와줄 스크립트입니다. 기존에는 tokcript라는 스크립트에 모두 내장되어 있었지만, commit을 제외한 각각의 기능은 모듈화되어 사용됩니다.- commit
- 사내 커밋 컨벤션에 맞게 커밋메시지 작성을 도와주는 스크립트 입니다.
- [AS-IS] gen:api [TO_BE] cli-plugin-gen-api-react-query
- swagger를 조회하여 api 함수와 schema type, react-query의 query, mutation을 생성해 줍니다.
- [AS-IS] gen:route [TO_BE] cli-plugin-gen-route-pages
- pages 폴더를 조회하여 route 경로를 담은 오프젝트를 생성해 줍니다.
- [AS-IS] convert:webp [TO - BE] cli-plugin-convert-webp
- sset 폴더를 조회하여, png, jpg 확장자를 webp로 변환해 줍니다. 변환하여 사용하기 전에, next/image 사용을 고민해 주세요. 다른 확장자를 사용하더라도 자동으로 webp 변환해줍니다.
- [AS-IS] gen:source [TO - BE] cli-plugin-gen-route-pages
- page, dynamic-page, api에 대한 탬플릿을 생성해 줍니다.
- [AS-IS] gen:img [TO-BE] cli-plugin-gen-img
- asset 폴더를 조회하여 img 파일경로를 담은 Object를 생성해 줍니다
- [AS-IS] gen:icon [TO-BE] cli-plugin-gen-icon
- asset 폴더를 조회하여 svg 파일을 사용가능한 chakra-icon 컴포넌트로 생성해 줍니다.
- [AS-IS] gen:img [TO-BE] cli-plugin-gen-img
- asset 폴더를 조회하여 img 파일경로를 담은 Object를 생성해 줍니다
- [AS-IS] gen:icon [TO - BE] cli-plugin-gen-icon
- asset 폴더를 조회하여 svg 파일을 사용가능한 chakra-icon 컴포넌트로 생성해 줍니다.
- [AS - IS] gen:font [TO - BE] cli-plugin-gen-font
- asset 폴더를 조회하여 font 파일을 next-local 폰트로 생성해 줍니다.
- commit
- universal
- 공통으로 사용되는 utils, hooks 모음입니다.
- react-universal
- React기반 framework에서 공통으로 사용되는 utils, hooks 모음입니다.
- react-app
- React기반 App framework 에서 공통으로 사용되는 utils, hooks 모음입니다. (React Native)
- react-web
- React기반 Wpp framework 에서 공통으로 사용되는 utils, hooks 모음입니다. (Next)
- node
- Node.js 환경에서 사용되는 유틸리티와 도구를 제공하는 패키지입니다. 이 패키지는 파일 시스템 작업, 프로세스 관리, 경로 조작 등 Node.js 환경에서 자주 사용되는 작업을 수행하는 함수와 클래스를 포함할 수 있습니다.
사용 개발 도구
1. 모노레포 관리: turborepo
Turborepo는 JavaScript와 TypeScript 코드 베이스의 모노레포를 위한 고성능 빌드 시스템으로, 캐싱 기능을 통해 반복 작업을 줄일 수 있습니다. 특히 Remote Caching 기능이 강력한데, 이는 CI/CD뿐만 아니라 팀원 간에도 캐싱된 빌드를 공유할 수 있습니다.
turborepo는 JavaScript와 TypeScript 코드 베이스의 모노레포를 위한 고성능 빌드 시스템으로 캐싱기능이 있어 한 번 작업된 계산은 다시 수행하지 않습니다.
2. 빌드: tsup
저희는 번들링을 위해 swc, rollup (with Gulp), tsup을 사용했고, 그중 가장 간단하면서 최적화된 번들러라 생각되는 tsup을 최종 선택하게 되었습니다.
tsup은 TypeScript 라이브러리를 번들링 하기 위한 도구로, 복잡한 설정이나 별도의 플러그인 설치 없이도 사용하기 쉽습니다. 이 도구는 Node.js의 CommonJS와 ESM 모듈 시스템을 모두 지원하며, 각각의 cjs, mjs 파일로 간단하게 컴파일할 수 있습니다. 또한, 다른 번들러와는 달리 타입 정의 파일도 자동으로 생성됩니다.
번들링 도구를 사용하고 정리한 글은 추후 정리하여 올리겠습니다.
tsup에서 CSS 번들링은 아직 실험적 단계입니다.
CommonJS와 ESM을 모두 지원해야 하는 이유에 대해서는 토스 기술블로그의 "CommonJS와 ESM에 모두 대응하는 라이브러리 개발하기: exports field" 글을 참조하시면 좋을 것 같습니다.
3. 패키지 매니저: pnpm
pnpm은 npm, yarn과 같이 JavaScript 프로젝트를 위한 패키지 매니저입니다. 사내에서는 이전에 yarn을 사용하고 있었습니다.
그러나 yarn이나 npm과 같은 패키지 매니저는 "유령 의존성" 문제를 일으킬 수 있습니다. 이는 패키지 매니저가 복잡한 의존성 구조를 단일 루트 디렉터리에 위치시키면서 발생하는 문제로, 중복 패키지 저장이나 설치되지 않은 패키지의 설치 등을 포함하며, 이로 인해 잠재적인 버그나 보안 위험을 초래할 수 있습니다.
반면에 pnpm은 node_modules에 직접 패키지를 설치하는 대신, 가상의 전역 저장소에서 패키지를 공유하는 방식을 사용합니다. pnpm이 패키지를 설치할 때는 package.json에 명시된 패키지를 읽은 후 node_modules에 설치합니다. 이 방식은 패키지 관리를 더욱 효율적이고 안전하게 만들어 줍니다. 중복된 패키지를 설치하지 않기 때문에 디스크 공간까지 절약되는 이점도 누릴 수 있습니다.
또한, pnpm 은 모노레포를 지원하여 실제로 업무의 효율성이 올라갔습니다.
pnpm --filter [packageName]으로 간단하게 하위 패키지의 스크립트를 실행할 수 있습니다.
4. 버전 관리 & 변경 로그: Changesets
Changesets은 프로젝트에서 버전 관리와 변경 로그 생성을 도와주는 도구입니다. 기존에 사내에서는 단일 레포지토리에서 semantic-release를 사용하고 있었는데요. Changesets으로 변경하게 된 계기는 다음과 같습니다.
- semantic-release는 커밋 메시지 기반으로 버전을 자동으로 결정하지만, Changesets은 개발자가 직접 변경 사항에 대한 설명과 버전 업데이트의 종류(major, minor, patch)를 결정할 수 있습니다.
- semantic-release는 별도의 플러그인을 통해 모노레포를 지원하지만, Changesets은 기본적으로 모노레포를 지원합니다.
- semantic-release는 CI 환경에서 main브랜치에 병합될 때마다 자동으로 버전을 업데이트하지만 Changesets은./changesets폴더의 임시 md파일을 읽어 해당 md파일이 포함된 커밋이 병합이 되면, [Version Packages]라는 PR생성을 통해 배포여부를 결정할 수 있습니다.
note. 이 기능은 Changesets GitHub App & Changesets GitHub Action의 조합으로 사용할 수 있습니다.
Changesets를 사용하면서 느낀 장점 중 하나는, 모노레포를 사용하는 것뿐만 아니라, 배포를 개발자가 직접 결정할 수 있어 잘못된 배포를 방지할 수 있다는 것입니다.
5. 문서 자동화: api-extractor & docusaurus
모노레포에 패키지 수가 많아지면서 문서 작성에 대한 부담감이 커졌습니다. 저희는 수기로 직접 문서를 작성하기보다는, 코드 주석에서 문서를 추출하는 방법을 찾게 되었고, 이를 위해 Microsoft의 api-extractor를 사용하기로 결정했습니다.
api-extractor는 TypeScript 라이브러리에서 API를 추출하고 문서화하는 데 사용됩니다. 라이브러리의 공개 API를 분석하고, 변경을 추적하기 용이한 기능도 있지만 저희는 추출된 API를 이용하여 md파일을 생성해 주는 기능만을 사용하고 있습니다.
각 패키지의 주석을 읽어 JSON 파일로 출력하고, api-documentor를 사용하여 이를 Markdown 파일로 변환하였습니다. 이렇게 생성된 Markdown 파일을 스크립트를 통해 구조화하고, Docusaurus를 사용하여 웹사이트를 생성하였습니다.
초반에는 추출된 API를 @next/mdx를 통해 웹사이트를 구축하였지만, 검색 기능, 소개 페이지, 스타일링 등 많은 기능이 필요하게 되었습니다. 이러한 기능들은 Docusaurus에서 이미 제공하고 있어, Docusaurus를 사용하는 것이 더 효율적이라는 판단 하에 선택하게 되었습니다.
이렇게 하여, CI/CD와 함께 문서도 자동화하였습니다.
6. CI/CD 최적화 및 관리
저희는 자동화를 위해 Github Action을 적극적으로 활용하고 있습니다. workflow를 composite를 사용해 역할을 분리하여 합성하고,
의존성 설치, 빌드 캐싱등을 통해 빌드시간을 단축시키고 있습니다.
적용하면서 많은 이슈를 겪었고 문서와 커뮤니티를 활용하여 해결하였습니다. 겪었던 부분들은 다 기록을 해두었으니, 차차 기술하겠습니다.
아직 작업을 다 마친 것은 아니고, 구현해야 할 사항이 많아 업데이트가 많이 될 것 같습니다. 지켜봐 주시면 감사하겠습니다.
'git > monorepo' 카테고리의 다른 글
[귀찮은건 질색이야-1] 24개 패키지 버전 관리 자동화 시키기: Changesets (0) | 2024.09.02 |
---|
- Total
- Today
- Yesterday
- React Query
- network
- 프로그래머스 자바스크립트
- python
- 리액트네이티브
- html
- github
- 자바스크립트 비동기 처리
- 프로그래머스
- 리액트
- 클로저
- 모두를 위한 컴퓨터 과학
- 모두를위한컴퓨터과학
- GIT
- React
- 네트워크
- 자바스크립트 클로저
- 항해99
- reactquery
- 자바스크립트알고리즘
- css
- 백준
- cs50
- 무한스크롤
- javascript
- 실전프로젝트
- 타입스크립트
- 프로그래머스 베스트앨범 자바스크립트
- 자바스크립트
- 알고리즘자바스크립트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |