티스토리 뷰

반응형

 

올해 시스템 업무를 시작하면서 가장 먼저 계획한 일은 보일러플레이트의 모노레포화입니다. 보일러플레이트는 초기 세팅에 필요한 코드나 공통으로 사용되는 컴포넌트, 유틸, 훅 등이 모여 있는데요. 보일러플레이트가 점점 발전하고 코드가 추가됨에 따라 버전 관리가 역할별로 분리되어야 할 필요성을 느꼈습니다. 특히, Next.js 13 버전부터 앱 라우터를 사용하게 되면서 기존의 페이지 라우터 방식과 앱 라우터 방식의 보일러플레이트가 각각 필요해졌습니다. 이외에도 다양한 이유로 인해 해당 작업이 필요하게 되었습니다.

 

처음으로 모노레포를 작업하는 일이라 시도해본 툴이나, 이슈가 많았는데요. 오늘은 모노레포를 적용하게 된 계기와 패키지 리스트, 사용한 개발 툴에 대해서 소개하겠습니다. 

 

해당 글을 기반으로 다음 글에서 사용한 개발 툴에 대해 자세하게 기술하겠습니다.

개요

보일러 플레이트를 monorepo로 이관합니다. 

 

목적

1. 공통 컴포넌트, 유틸, 훅 라이브러리화 

필요한 기능만 import해서 쓰는 방식으로 빌드 경량화, 모듈분리로 사용성을 개선시킵니다. 

 

2. Next.js app-router, page-router를 개별 템플릿으로 관리

CLI 방식으로 애플리케이션을 생성하며 모노레포 안에서 관리합니다.

명령어로 next app / page router, react query version 4, 5 여부 등을 선택해 로컬 경로에 바로 애플리케이션을 설치해 줍니다.

  • 기존 github repository template 생성을 매번 해야 했던 번거로움이 사라집니다. 

 

3. CLI (gen img, gen icon, gen api, gen webp..), hooks, utils, components 개별 모듈화

  • 실무자분들의 기여도를 높일 수 있습니다. 
  • 사용하는 모듈만 사용해 빌드 사이즈를 줄여줍니다. 
  • 의존하는 라이브러리의 변경사항이 많아지더라도 버전 관리가 독립적으로 되기 때문에 관리, 이슈대응이 편해집니다. 

 

4. CICD 

각 모듈의 버전 관리를 하며 패키지가 배포되면 changelog, releasenote가 생성됩니다.

 

 

기대

  • 관리상 편함과 history 추적을 쉽게 합니다.
  • hooks utils 등을 모듈화 시켜, 모든 경우에 대응하지 않는 모듈도 포함하여 기존 실무자분들의 기여도를 높입니다.
  • 프로젝트 클론, 배포까지의 과정을 CLI로 자동화하여 작업 효율을 높입니다.

 

 


Npm Package List

Scope : toktokhan-fe (임시)

 

  • 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 폰트로 생성해 줍니다.
  • 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 코드 베이스의 모노레포를 위한 고성능 빌드 시스템으로 캐싱기능이 있어 한 번 작업된 계산은 다시 수행하지 않습니다. 

 

turborepo를 사용하면서 가장 강력하다고 느꼈던 점은 Remote Caching 기능입니다. turbo를 사용하면 기본적으로 로컬 캐싱이 되지만, 몇 가지 설정만으로 원격캐싱까지 가능해집니다. CI/CD 뿐만 아니라 팀원 모두가 캐싱된 빌드를 공유할 수 있습니다. 

공식문서 참조: Remote Cacing

 


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를 사용해 역할을 분리하여 합성하고, 

의존성 설치, 빌드 캐싱등을 통해 빌드시간을 단축시키고 있습니다. 

 


적용하면서 많은 이슈를 겪었고 문서와 커뮤니티를 활용하여 해결하였습니다. 겪었던 부분들은 다 기록을 해두었으니, 차차 기술하겠습니다. 

 

아직 작업을 다 마친 것은 아니고, 구현해야 할 사항이 많아 업데이트가 많이 될 것 같습니다. 지켜봐 주시면 감사하겠습니다.

 

 

 

 

 

 

 

 

 

 

반응형