gitgitWi
Wii-World

Wii-World

Yarn Berry 적용 1일차에 느낀 점 (Nest.js, Fastify ⤴️ / TurboRepo ⤵️)

Yarn Berry 적용 1일차에 느낀 점 (Nest.js, Fastify ⤴️ / TurboRepo ⤵️)

주간회고 01. 리팩토링하다가 Yarn Berry 적용한 이야기

gitgitWi's photo
gitgitWi
·Jan 16, 2022·

5 min read

Subscribe to my newsletter and never miss my upcoming articles

Table of contents

image.png

저와는 무관한 짤입니다

3줄 요약

  • 사내 GitLab-CI로 브랜치 머지를 하는데, feature ➡️ develop에선 잘 되던 게 develop ➡️ master에선 yarn.lock 파싱을 못하는 오류 발견
  • 일부 패키지 버전을 0.0.1씩 낮춰보는 삽질을 하다, Yarn berry 도입
  • turborepo 등 모노레포 툴을 굳이 안써도 될 정도로 workspaces가 편리해졌고, PnP 모드는 Nest.js+Fastify에서 호환이 잘 안되는 듯해서 사용하지 못함

???구현 다해놨는데 배포가 외않되???

지난 주부터 진행해 온 Koa.jsNest.js + Fastify 차트 서버 프레임워크 변경 작업이 거의 마무리 단계다

부끄럽게도 개발인생 처음으로 TDD 방식 리팩토링을 진행했고, 우여곡절 끝에 e2e 테스트만 활용하여 테스트 커버리지 약 90%를 달성하고 구현을 마무리했다 (사실 단위 테스트는 하다가 머리 빠질 것 같아서 포기한 것..)

feature ➡️ develop 머지하는 과정에서 사내 GitLab-CI에서 아주 깔끔하게 테스트를 통과했고,

image.png

당연히 여유롭게 배포를 마무리하고, 상쾌한 기분으로 주말을 보낼 수 있을 줄 알았다..

문제는 develop ➡️ master 머지 과정에서, 구글링을 해도 나오지 않는 에러 메시지가 계속 발생했다

모노레포 빌드 타임을 줄이기 위해 turborepo를 사용하고 있는데, turbo 명령어를 쓰자마자 yarn.lock에 특정 패키지 이름이 중복된 키로 들어가 있다며 unmarshal 에러를 던지는 것이다

그러나 yarn.lock에서 해당 패키지 이름을 검색해보면 중복되게 키 값이 설정된 경우는 없었고, node_modules, yarn.lock, 캐시 관련 디렉토리 모두 지우고 다시 설치해봐도 동일한 문제가 발생했다

며칠 전 turborepo 마이너 업데이트에서 문제가 발생한 게 아닐까 추측했다

그래서 turborepo 마이너 버전을 하나씩 내리면서(1.0.28 -> 1.0.25) 브랜치 머지를 해봤는데, 이제는 아예 feature ➡️ develop 머지할 때도 동일한 에러가 나버렸다;; 대체 이게 머선129..

turborepo 뿐만 아니라 지금까지 추가로 설치한 모든 패키지들을 이런 식으로 하나씩 테스트를 해볼 수는 없다

그렇다고 이제와서 프레임워크 전환을 아예 돌려버리기엔 너무 먼 길을 떠나온 느낌이었다

그래서 아예 패키지 매니저를 바꿔보면 어떨까, Yarn1 -> Yarn Berry로 바꿔보면 어떨까하는 생각을 하게 된다


Yarn Berry; 만남은 쉽고 응용은 어려워

Yarn BerryNPM, Yarn1에서 사용하는 node_modules 체계에서 아예 벗어나 새로운 체계를 만든 거여서 그런지 여러모로 새로운 부분들이 많았다

yarn install을 했을 때, 의존성 패키지 파일들을 압축파일(.zip)로 다운받아서 <rootDir>/.yarn/cache에 저장하는 부분부터 새롭다

image.png

PnP 모드를 사용하면, 이 압축파일들 그 자체를 활용할 수 있고,

여기에 Zero-install 방식을 더하면, 이 패키지 파일들도 Git에 저장하여 추가 설치 없이, yarn.lock의 방해(?)를 받지 않고 바로 CI/CD 과정에서 활용할 수 있어 배포 시간을 크게 줄일 수 있다


Yarn Workspaces, 간단한 모노레포 관리에 딱!

아쉽게도 turborepoYarn Berry와 호환되지 않기 때문에 더이상 사용할 수 없었고, Nx나 다른 대안을 찾아봐야했다

NxLerna도 한번쯤 사용해고 싶던 기술이긴 했지만, 최근 계속해서 Nest.js, Fastify, Yarn Berry 등 처음 써보는 스택들을 공부하면서 바로 적용하는 과정이 이어지다보니, 뭔가를 더 공부하기는 조금 벅차다고 느껴졌다

한편 토스 기술블로그에서 workspaces 기능 완성도가 높아서 내부에서 적극 활용 중이라는 걸 보고 관련 옵션들을 찾아보았다

image.png

  • 대혼돈에 빠진 모노레포 패키지별 스크립트; 이것도 나름 스크립트를 축약해서 쓸 수 있는 방법이었다

사실 turborepo를 쓸 때에도 엄청난 기능을 사용했던게 아니라, 병렬적으로 빌드하고 동일한 스크립트를 전체 패키지에서 한번에 실행하는 정도였다

image.png

  • 스크립트가 훨씬 프로그래머틱해졌다

workspaces foreach를 활용하면, 굳이 이런 모노레포 관리툴을 사용하지 않아도 간단한 패키지 관리는 충분하다

turborepo에서 불편했던 점은, server 패키지를 제외한 나머지 components, pages 패키지들만 빌드하고 싶어서 scope 옵션을 사용하더라도, server에서 의존하고 있는 것 때문에 강제로 전체 패키지를 빌드하게 됐던 점이다

workspaces foreach--include/--exclude 옵션으로 의존성과 관계없이 좀더 직관적으로 필요한 패키지를 지정해서 명령할 수 있고,

image.png

-p,--parallel, -t,--topological 옵션을 합치면 turborepo build와 동일하게 의존성 순서대로 병렬적인 빌드 명령을 내릴 수 있다!

workspace.nohoist를 지정하지 않아도 된다!

증시맵 차트 구현을 위해 D3를 사용하고 있는데, 5버전까지만 IE(ES5)를 지원하고 6버전부터는 ES6+ 문법으로 쓰여져서 IE를 지원하지 않는다

이 때문에 맵 컴포넌트/페이지 패키지를 따로 관리하고 있고, yarn workspaces에서 의존성은 기본적으로 hoist 되기 때문에, D3 5버전 타입과 6버전 타입이 충돌하는 문제가 있었다

image.png

그래서 Yarn1 workspaces에서는 nohoist 옵션을 지정하여 IE 관련 패키지에서는 패키지 내부에 node_modules 디렉토리를 따로 생성하도록 했다

image.png

Yarn Berry에서는 모든 의존성을 hoist 하되, 각 패키지의 package.json에 명시된 버전을 정확히 지켜준다(?)

덕분에 nohoist된 패키지들의 의존성 중복을 줄여주는 효과를 가져오고, 관리하기도 좀더 편리해졌다

Plug'n'Play, 너무 좋아보이는데 쓸 수가..

너무나도 아쉬운 점은 현재 차트 서버에서는 PnP 모드를 사용하기 어렵다는 점이다

PnP 모드와 Zero-install 설정에 대한 소개글을 보면서, 이것으로 배포에 걸리는 시간도 크게 단축시킬 수 있다는 희망(?)을 가질 수 있었다


고비는 압축파일로 된 의존성 패키지였다

정확한 이유는 아직 파악하지 못했지만, 의존성 패키지가 의존하는 패키지를 코드에서 import 할 때 해당 패키지를 찾지 못하는 문제가 종종 발생했다

image.png

일반적으로 위 코드처럼 fastify 패키지를 가져와서 쓸 수 있는 이유는, yarn add fastify로 직접 설치하고 package.json에 패키지명을 명시했기 때문에 가져올 수 있는 것이 아니다

image.png

yarn add @nestjs/platform-fastify를 하면 @nestjs/platform-fastify가 내부적으로 fastify를 의존하고 node_modules 안의 node_modules를 만들기 때문에, 함께 설치가 되어서 가져올 수 있는 것이다

그러나 PnP 모드에서는 가끔 패키지를 아예 인식하지 못하는 경우가 있고, yarn add fastify로 추가하거나 yarnrc.yml packageExtensions에 문제가 있는 패키지들을 적어주면 해결할 수 있다(고 한다..)

그런데 서버 패키지에서는 계속 꼬리에 꼬리를 물고 에러를 던지는 상황이 벌어졌고,

클라이언트 패키지들에서는 모노레포 root package.json공용 의존성으로 선언한 의존성 패키지들, 특히 Webpack, TypeScript들을 인식하지 못해서, 공용 의존성 패키지들을 각 패키지 내부에서 다시 설치해서 선언해줘야 하는 문제가 있었다

방법을 제대로 찾지 못한 걸 수도 있지만, 이건 도저히 귀찮아서 못써먹겠다는 생각에 node_modules를 다시 사용하기로 했다..

Yarn Berry X _node_modules_ 공존하기

물론 다시 Yarn1이나 NPM으로 돌아가는 것이 아니다

공식문서에도, 모노레포 환경에서 PNP 모드와 node_modules를 동시에 활용하는 방법을 제시한다

# .yarnrc.yml
nodeLinker: node-modules

위와 같이 node_modulesnodeLinker로 사용한다고 지정하면, 사라졌던 node_modules 디렉토리가 부활하여 .yarn/cache가 공존하게 되고, 이전처럼 중첩된 의존성 패키지들도 가져와서 사용할 수 있게 된다

한편 Zero-install은 아니고 0.5-install 정도로 활용할 수 있게, .yarn/cache를 Git으로 관리하도록 했다

이렇게만 하더라도 사내 Jenkins를 기준으로

image.png

image.png

  • yarn install 소요시간을 기존 40~60초에서 👉 15~30초대로 절반 가량 줄였고,

image.png

image.png

  • 특히 재밌는 점은 빌드 후 docker-registrypush하는 시간이 1분30초대 👉 30초대로 크게 줄어든 점이다

이 부분도 추측해보면, 기존 node_modules만 가지고 빌드하는 경우 node_modules 폴더만 용량이 850mb 이상인데, .yarn/cachezip 파일들로만 구성되다보니 170mb 정도로 용량이 크게 줄었고,

빌드된 도커 이미지도 그에 따라 크게 줄었기 때문이 아닐까하는 생각이 든다


참고자료

 
Share this