저와는 무관한 짤입니다
- 사내
GitLab-CI
로 브랜치 머지를 하는데,feature
➡️develop
에선 잘 되던 게develop
➡️master
에선yarn.lock
파싱을 못하는 오류 발견- 일부 패키지 버전을 0.0.1씩 낮춰보는 삽질을 하다,
Yarn berry
도입- turborepo 등 모노레포 툴을 굳이 안써도 될 정도로
workspaces
가 편리해졌고, P&P 모드는Nest.js+Fastify
에서 호환이 잘 안되는 듯해서 사용하지 못함
지난 주부터 진행해 온 Koa.js
→ Nest.js + Fastify
차트 서버 프레임워크 변경 작업이 거의 마무리 단계다
부끄럽게도 개발인생 처음으로 TDD 방식 리팩토링을 진행했고, 우여곡절 끝에 e2e 테스트만 활용하여 테스트 커버리지 약 90%를 달성하고 구현을 마무리했다 (사실 단위 테스트는 하다가 머리 빠질 것 같아서 포기한 것..)
feature
➡️ develop
머지하는 과정에서 사내 GitLab-CI
에서 아주 깔끔하게 테스트를 통과했고,
당연히 여유롭게 배포를 마무리하고, 상쾌한 기분으로 주말을 보낼 수 있을 줄 알았다..
문제는 develop
➡️ master
머지 과정에서, 구글링을 해도 나오지 않는 에러 메시지가 계속 발생했다
모노레포 빌드 타임을 줄이기 위해 turborepo
를 사용하고 있는데, turbo
명령어를 쓰자마자 yarn.lock
에 특정 패키지 이름이 중복된 키로 들어가 있다며 unmarshal
에러를 던지는 것이다
yarn.lock: could not unmarshal lockfile
turborepo
이슈에 등록된 내용인데, 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 Berry
는 NPM
, Yarn1
에서 사용하는 node_modules
체계에서 아예 벗어나 새로운 체계를 만든 거여서 그런지 여러모로 새로운 부분들이 많았다
yarn install
을 했을 때, 의존성 패키지 파일들을 압축파일(.zip
)로 다운받아서 <rootDir>/.yarn/cache
에 저장하는 부분부터 새롭다
PnP 모드를 사용하면, 이 압축파일들 그 자체를 활용할 수 있고,
여기에 Zero-install 방식을 더하면, 이 패키지 파일들도 Git에 저장하여 추가 설치 없이, yarn.lock
의 방해(?)를 받지 않고 바로 CI/CD 과정에서 활용할 수 있어 배포 시간을 크게 줄일 수 있다
Yarn Workspaces
, 간단한 모노레포 관리에 딱!아쉽게도 turborepo
는 Yarn Berry
와 호환되지 않기 때문에 더이상 사용할 수 없었고, Nx
나 다른 대안을 찾아봐야했다
Nx
나 Lerna
도 한번쯤 사용해고 싶던 기술이긴 했지만, 최근 계속해서 Nest.js
, Fastify
, Yarn Berry
등 처음 써보는 스택들을 공부하면서 바로 적용하는 과정이 이어지다보니, 뭔가를 더 공부하기는 조금 벅차다고 느껴졌다
한편 토스 기술블로그에서 workspaces
기능 완성도가 높아서 내부에서 적극 활용 중이라는 걸 보고 관련 옵션들을 찾아보았다
사실 turborepo
를 쓸 때에도 엄청난 기능을 사용했던게 아니라, 병렬적으로 빌드하고 동일한 스크립트를 전체 패키지에서 한번에 실행하는 정도였다
workspaces foreach
를 활용하면, 굳이 이런 모노레포 관리툴을 사용하지 않아도 간단한 패키지 관리는 충분하다
turborepo
에서 불편했던 점은, server
패키지를 제외한 나머지 components
, pages
패키지들만 빌드하고 싶어서 scope
옵션을 사용하더라도, server
에서 의존하고 있는 것 때문에 강제로 전체 패키지를 빌드하게 됐던 점이다
workspaces foreach
는 --include/--exclude
옵션으로 의존성과 관계없이 좀더 직관적으로 필요한 패키지를 지정해서 명령할 수 있고,
-p,--parallel
, -t,--topological
옵션을 합치면 turborepo build
와 동일하게 의존성 순서대로 병렬적인 빌드 명령을 내릴 수 있다!
workspace.nohoist
를 지정하지 않아도 된다!증시맵 차트 구현을 위해 D3를 사용하고 있는데, 5버전까지만 IE(ES5)를 지원하고 6버전부터는 ES6+ 문법으로 쓰여져서 IE를 지원하지 않는다
이 때문에 맵 컴포넌트/페이지 패키지를 따로 관리하고 있고, yarn workspaces
에서 의존성은 기본적으로 hoist 되기 때문에, D3 5버전 타입과 6버전 타입이 충돌하는 문제가 있었다
그래서 Yarn1 workspaces
에서는 nohoist
옵션을 지정하여 IE 관련 패키지에서는 패키지 내부에 node_modules 디렉토리를 따로 생성하도록 했다
Yarn Berry
에서는 모든 의존성을 hoist 하되, 각 패키지의 package.json
에 명시된 버전을 정확히 지켜준다(?)
덕분에 nohoist
된 패키지들의 의존성 중복을 줄여주는 효과를 가져오고, 관리하기도 좀더 편리해졌다
Plug'n'Play
, 너무 좋아보이는데 쓸 수가..너무나도 아쉬운 점은 현재 차트 서버에서는 PnP 모드를 사용하기 어렵다는 점이다
PnP 모드와 Zero-install 설정에 대한 소개글을 보면서, 이것으로 배포에 걸리는 시간도 크게 단축시킬 수 있다는 희망(?)을 가질 수 있었다
고비는 압축파일로 된 의존성 패키지였다
정확한 이유는 아직 파악하지 못했지만, 의존성 패키지가 의존하는 패키지를 코드에서 import
할 때 해당 패키지를 찾지 못하는 문제가 종종 발생했다
일반적으로 위 코드처럼 fastify
패키지를 가져와서 쓸 수 있는 이유는, yarn add fastify
로 직접 설치하고 package.json
에 패키지명을 명시했기 때문에 가져올 수 있는 것이 아니다
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_modules
를 nodeLinker
로 사용한다고 지정하면, 사라졌던 node_modules
디렉토리가 부활하여 .yarn/cache
가 공존하게 되고, 이전처럼 중첩된 의존성 패키지들도 가져와서 사용할 수 있게 된다
한편 Zero-install은 아니고 0.5-install 정도로 활용할 수 있게, .yarn/cache
를 Git으로 관리하도록 했다
이렇게만 하더라도 사내 Jenkins
를 기준으로
yarn install
소요시간을 기존 40~60초에서 👉 20~40초대로 줄였고,docker-registry
에 push
하는 시간이 1분30초대 👉 30초대로 크게 줄어든 점이다이 부분도 추측해보면, 기존 node_modules
만 가지고 빌드하는 경우 node_modules
폴더만 용량이 850mb 이상인데, .yarn/cache
는 zip
파일들로만 구성되다보니 170mb 정도로 용량이 크게 줄었고,
빌드된 도커 이미지도 그에 따라 크게 줄었기 때문이 아닐까하는 생각이 든다