2022. 8. 7. 17:10ㆍFrontend
Overview
모노레포의 문화적 의의를 다룬 이전 포스팅에 이어, 이번 포스팅 시리즈에서는 실제로 모노레포를 팀에 도입하기 위해 거쳐왔던 여러 기술적인 고려 사항들을 간단하게 이야기해보려고 합니다. "모노레포는 이렇게 운영하는 것이 좋다"라는 가이드라기보다는 프론트엔드 팀이 모노레포로 전환하는 과정에서 겪은 여러 문제들과, 이를 해결해 나가는 과정에 대한 기록에 가까울 것 같습니다. 글은 다음과 같은 순서로 작성되었습니다.
- Workspaces & Dependencies
- Global Lint & Prettier
- Deploy & Branch Management
- Plugin
- (Optional) Sparse Checkout
Yarn Plugin
Yarn Berry(v2) 부터 공식적으로 plugin에 대한 지원이 추가됩니다. 앞서 모노레포에 대한 모든 설정들을 Yarn Berry의 workspace를 통해 개발하였기 때문에, 모노레포에서도 yarn plugin을 사용할 수 있습니다. plugin을 사용하면 기존에 팀들이 수동으로 여러 번의 절차를 거쳐야 하는 어렵지 않지만 번거로운 작업들을 한두 개의 커맨드로 쉽게 통합할 수 있습니다.
Plugins are scripts that get loaded at runtime by Yarn, and that can inject new behaviors into it. They also can require some packages provided by Yarn itself, such as @yarnpkg/core. This allows you to use the exact same core API as the Yarn binary currently in use, kinda like if it was a peer dependency!
Plugin을 사용하면 yarn에서 제공하는 core API 및 Lifecycle Hook(etc. After Installed Hook)을 사용할 수 있기 때문에 패키지 설치 전과 후에 실행되어야 하는 커맨드나, 기존에 터미널에서 사용하는 커맨드들을 스크립트화 하여 레포지토리에서 관리할 수 있습니다.
콴다 프론트엔드 팀은 크게 2가지 Workflow를 단순화하기 위해 Plugin을 사용하고 있습니다. 첫 번째 Plugin은 `yarn deploy` 입니다. 모노레포를 사용해서 여러 프로젝트들을 여러 팀원들이 개발할 때, 저희 팀에서는 브랜치 전략으로 Trunk Based Development 전략을 사용하고 있습니다. 따라서 배포는 main브랜치의 commit에 Release Tag를 달아서 배포하는 Tag Based Deployment 전략을 사용하게 됩니다. 이때, 매번 규칙에 맞는 새로운 태그를 작성하는 것이 번거롭기도 하고, 오타의 가능성도 있기 때문에 이를 `yarn deploy` 라는 커맨드를 사용해서 단순하게 태그를 생성하고 푸쉬하는 flow를 만들었습니다.
yarn deploy를 모노레포에서 입력하면 현재 모노레포에 있는 모든 서비스들이 리스트로 나오게 됩니다. (서비스가 모노레포에 추가되면 별도의 등록과정 없이 플러그인이 알아서 읽어오게 됩니다.) 여기서 배포할 서비스를 선택한 후 엔터를 누르면 환경을 선택하는 화면이 나오게 됩니다.
환경을 선택하고 나면, Origin에서 현재 생성되어 있는 태그들의 정보를 가져옵니다. (적절히 서비스 이름, 날짜 등으로 필터링해서 가져옵니다.) 그 후, 규격에 맞게 최신 태그를 생성해주고 한번 더 Confirm 하는 과정을 거치게 됩니다.
Confirm이 완료된다면, 해당 태그를 Remote Origin에 Push하고 Q-Principle(콴다에서 가장 중요하게 생각하는 5가지 원칙)중 하나를 랜덤으로 보여주며, 배포 빌드가 돌게 되는 Jenkins Pipeline 링크를 보여줍니다. 이렇게 deploy 플러그인을 만들게 되면서, 매번 github 페이지에 들어가서 Release Tag를 생성하고, 오타가 생기면 다시 생성하는 과정들을 커맨드 한 번으로 자동화할 수 있게 되었습니다.
두 번째 플러그인은 `yarn gcp-auth` 입니다. AWS에서 GCP로 사내 인프라가 넘어가면서 기존에 github packages를 사용하던 내부 라이브러리들을 gcp의 artifact registry로 이전하게 되었습니다. 이에 따라 로컬 개발 시, 빌드 시에 해당 라이브러리를 가져올 인증 정보가 수정되어야 했는데, 빌드 환경에서는 CloudBuild의 Service Account가 해당 registry의 접근 권한이 있어서 크게 문제가 없지만, 로컬 개발의 경우 각 개발자가 로컬에서 본인의 gcloud 계정을 가지고 해당 registry를 가져와야 했습니다.
따라서 24시간 정도의 만료 기간을 가지고 있는 gcloud 인증 토큰을 매번 교체해 주어야 했고, gcloud auth login을 하면 생성되는 토큰은. npmrc의 형태(rc file)로 제공되기 때문에, 이를 모노레포에서 사용하기 위해서. yarnrc.yml 에서 받아줄 수 있는 형태(yaml file)로 가공을 매번 해주어야 했습니다. 이 부분을 커맨드 하나로 해결하기 위해 `yarn gcp-auth` 플러그인을 만들었고, 해당 플러그인을 실행하면 gcloud auth login을 한 후에, 생성되는 토큰을 각자 개발 환경의 root .yarnrc.yml 파일에 주입하게 됩니다.
콴다 프론트엔드 팀은 위 두 개의 플러그인을 사용해서 개발 생산성을 크게 높일 수 있었으며, 이렇게 만들어 둔 플러그인들을 바탕으로 필요할 때마다 팀원들과의 논의를 거쳐서 여러 플러그인들을 추가하고 있습니다.
Yarn Plugin Example - Deploy Plugin
위에서 이야기한대로, 간단하게 Typescript가 호환되는 yarn plugin을 만드는 방법에 대해 살펴보겠습니다. 아래에서 소개한 `yarnpkg-builder`를 사용하면 이를 쉽게 만들 수 있습니다. 해당 라이브러리를 모노레포의 root devDependencies로 설치해 줍니다.
https://github.com/yarnpkg/berry/tree/master/packages/yarnpkg-builder
Create New Plugin
아래와 같은 명령어를 입력하면 모노레포의 plugins 디렉토리 안에 다음과 같이 새로운 플러그인이 생성되도록 만들 수 있습니다. 성공하고 나면 아래와 같이 새로운 플러그인이 생기는 것을 확인할 수 있습니다.
Build New Plugin
해당 플러그인은 별도의 node_modules 를 가지므로 해당 플러그인 디렉터리 안에 yarn.lock 파일(빈파일)을 추가해주고 해당 디렉터리 안에서 yarn install을 실행합니다. 실행하고 나면 다음과 같은 구조가 나오게 되는데, 여기에. gitignore를 추가해줍니다.(node_modules,. yarn 만 포함하면 됩니다)
Build Plugins
해당 플러그인의 디렉터리로 이동해서 다음 커맨드를 통해 플러그인을 빌드합니다.
yarn build
Import Plugins
다음으로는 실제로 이 플러그인을 .yarnrc.yml 에 등록해야 합니다. 아래와 같은 명령어를 모노레포의 루트 디렉터리에서 실행해줍니다.
yarn plugin import ./plugins/sample/bundles/@yarnpkg/plugin-helloworld.js
아래와 같이 추가된 플러그인이 등록된 것을 확인할 수 있습니다.
추가적으로 필요한 기능들이 있다면 clipanion, cli-select, exca 등의 라이브러리를 추가해서 다른 서비스들을 개발하듯이 플러그인을 개발할 수 있습니다.
Conclusion
Yarn Berry의 Workspace를 사용해서 개발된 모노레포라면, 자주 사용되는 Workflow를 Plugin으로 개발하는 것은 많은 이점을 가져다 주는 것 같습니다. 그러나 때때로 지나친 자동화는 오버엔지니어링이 되어 불필요한 팀의 리소스를 소모하게 되는 경우도 있기 때문에 단순한 기술적 흥미를 넘어서서 "어떤 Workflow를 Plugin으로 만들었을 때 팀의 생산성이 높아질까?"를 잘 생각해 보는 것이 Plugin을 만드는 것 만큼이나 중요하다는 생각이 듭니다.
Reference
https://yarnpkg.com/advanced/plugin-tutorial
https://yarnpkg.com/features/plugins#what-can-plugins-do
'Frontend' 카테고리의 다른 글
Declarative React, and Inversion of Control (0) | 2022.09.03 |
---|---|
모노레포의 기술적 요구사항 (5) - Sparse Checkout (0) | 2022.08.07 |
모노레포의 기술적 요구사항 (3) - Deploy / Branch 전략 (0) | 2022.08.07 |
모노레포의 기술적 요구사항 (2) - Global Lint / Prettier (0) | 2022.08.07 |
모노레포의 기술적 요구사항 (1) - Workspaces & Dependencies (0) | 2022.08.07 |