우리는 지금까지 NPM 패키지 매니저를 사용해왔다.
그러나 NPM 패키지 매니저에 관해서 항상 많은 문제점들이 제기되어 왔다.
https://toss.tech/article/node-modules-and-yarn-berry 해당 블로그에 정리가 매우 잘 되어있다.
다시 복기하는 겸 내 블로그에 작성하며 공부해보기로 했다.
비효율적인 의존성 검색
NPM 프로젝트에서 node에 진입 후 react 패키지를 찾는 상황을 연출해보자.
위에서 볼 수 있듯이 npm은 패키지를 찾기 위해 상위 디렉토리의 node_modules 폴더를 탐색하게 되고, 바로 찾지 못할 수록 느린 I/O 호출이 반복되게 된다고 한다(실패하기도 함).
환경에 따라 달라지는 동작
위에서 보았듯이 NPM은 패키지를 찾지 못하면 상위 디렉토리의 node_modules를 계속 탐색한다. 이러한 특성으로 인해 특정한 의존성을 찾을 수 있냐는 해당 패키지의 상위 디렉토리 환경에 따라 달라지게 된다.
이는 협업하기에 신뢰성이 떨어지는 동작이다.
비효율적인 설치
우선 node_modules의 크기는 어마무시하게 크다. node_modules는 용량을 많이 차지할 뿐만 아니라, 복잡한 구조로 인해 의존성 설치가 유효한지 검증하기도 어렵다,
유령 의존성(Phantom Dependency)
왼쪽 의존성 트리에서는 A(1.0)과 B(1.0) 패키지는 두번 설치되므로 디스크 공간을 낭비하게 된다. 이를 방지하기 위해 NPM과 Yarn v1 에서는 오른쪽 의존성 트리처럼 끌어올리기(Hoisting) 기법을 사용한다.
이 Hoisting 기법으로 인해 직접 의존하고 있지 않은 라이브러리를 require() 할 수 있는 현상을 유령 의존성이라고 부른다고 한다. 이러한 특성은 어떤 버그를 일으킬지 에측할 수 없어 의존성 관리를 혼란스럽게 만든다.
Yarn Berry 에서는 이러한 문제점이 많은 NPM 에서 벗어나 Plug`n`Play (PnP) 전략을 제시한다.
해당 전략을 Yarn Berry로 마이그레이션을 해보며 알아보도록 하자!!
✅윈도우(Windows)
✅React(Create React App + Typescript)
yarn 설치
yarn이 설치되어있지 않다면
npm install -g yarn
위 명령어를 통해 Yarn을 global로 설치해준다.
그 후 yarn -v 명령어로 yarn의 버전을 확인해보면 v.1.x.x로 되어있을 것이다. Yarn Berry는 Yarn의 버전이 v.2.x.x 이상이어야 하므로 이따가 업그레이드 해 줄 것이다.
node_modules & package-lock.json 삭제
Yarn Berry는 더이상 무거운 node_modules 의존성 폴더를 사용하지 않고 의존성 관리를 진행한다. 그러므로 현재 프로젝트에 있는 node_modules 폴더와 package-lock.json 파일을 삭제해준다.
yarn.lock 파일 생성
위와 같이 루트 경로에 yarn.lock 파일을 생성해준다.
yarn set version berry
yarn set version berry
위 명령어를 통해 Yarn Berry 버전으로 변경해준다.
yarn set version 버전
Yarn Berry 버전을 직접 맞춰주고 싶다면 위 명령어로 버전을 입력해주면 된다. 현재 기준 Yarn Berry 버전 4가 나왔는데 나는 아직 안정적인 버전 3을 선택했다.
위 명령어를 통해 Yarn Berry 버전으로 변경하면
위와 같이 .yarn 폴더와 .yarnrc.yml 파일이 생성된 것을 확인할 수 있다.
- .yarn 폴더안에 있는 yarn-버전.cjs 파일은 Yarn Berry환경을 구축하는 자바스크립트 파일이다. 그리고 Yarn Berry 환경에서 수행되는 모든 Yarn 동작은 이 yarn-버전.cjs 스크립트 위에서 수행된다고 한다.
- .yarnrc.yml 파일은 Yarn의 내부 설정을 관리하는 파일이다.
Plug`n`Play (PnP) 적용하기
.yarnrc.yml 파일의 내부를 들여다보자.
yarnPath: .yarn/releases/yarn-3.6.3.cjs
위와 같은 내용을 볼 수 있다.
yarnPath: .yarn/releases/yarn-3.6.3.cjs
nodeLinker: pnp
위와 같이 nodeLinker를 pnp로 설정해주자. nodeLinker를 node_modules가 아닌 pnp로 설정해주면 의존성이 Yarn Berry의 PnP 방식에서 생성되는 zip 아카이브로 관리됨을 보장해준다(아무것도 써주지 않아도 디폴트로 pnp가 적용된다고 하지만 나는 명시적으로 선언해주었다). 위와 같이 설정 후 yarn install 을 진행하면
위와 같이 더이상 node_modules는 생성되지 않고, .yarn폴더의 cache 폴더와 .pnp.cjs 파일이 생성된 것을 확인할 수 있다.
- .yarn 폴더 안의 cache 폴더에는 react와 의존성 패키지 정보가 zip 포맷으로 압축 저장된다. 패키지 설치 시간이 줄어들고, 의존성 압축을 통하여 디스크 용량도 절감된다.
- 이때 .pnp.cjs 파일에는 의존성을 찾을 수 있는 트리 정보가 기록된다. 패키지를 탐색하기 위한 비효율적인 디스크 I/O 과정으로부터 벗어날 수 있게 되었으며 의존성을 쉽게 검증할 수 있게 됨으로써 유령 의존성 문제도 해결될 수 있게 되었다고 한다. 또한 모든 의존성이 .pnp.cjs 파일을 통해 관리되기 때문에 외부 환경에 영향을 받지 않게 되었다. 이로써 개발환경에 따라 패키지 참조가 다르게 될 수 있는 문제도 사라졌다.
의존성을 가져오지 못할 때
우선 zip 파일로 설치된 의존성을 읽기 위해 vscode 익스텐션에서 ZipFS 를 설치한다.
그 후
yarn dlx @yarnpkg/sdks vscode
해당 명령어를 실행한다. 잘은 모르지만 VSCode 관련 도구를 사용하기 위해 필요한 도구를 가져와서 실행하는 것이라고 한다.
그 외의 오류
나는 Could not find a declaration file for module 'react/jsx-runtime'.
이런 오류 등을 마주쳤었다.
만약 이런 오류들을 마주친다면 Windows 기준 ctrl+shift+p 를 누른 후 'Select Typescript version' 에서 Use WorkSpace Version 으로 설정해준다.
Zero installs
Yarn Berry에서 사용하는 Zero installs를 사용하면 반복적으로 의존성 설치 작업을 하지 않아도 된다.
Yarn Berry의 Plug`n`Play (PnP) 에서는 의존성을 압축 파일로 관리하기 때문에 의존성의 용량이 작다. 따라서 의존성을 Git으로 관리할 수 있다. 즉, 파일 용량이 매우 큰 node_modules를 .gitignore에 지정해준 것과 달리 의존성 관련 파일들을 Github Repository에 올려 관리하는 방식이다.
해당 방식을 채택하면 저장소를 clone 하거나 브랜치 이동 시 의존성 관련 파일들이 따라오게 되므로 yarn install 단계가 빠지게 된다.
- Zero-installs를 사용 시
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
- Zero-installs를 사용하지 않을 때
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
방식은 자유롭게 선택하여 .gitignore에 위의 내용을 추가해주면 된다.
나는 Zero-installs 방식을 채택하였다. 이를 테스트해보기 위해 프로젝트를 다시 클론해온 후 yarn 명령어를 통해 yarn만 다시 설치해주었다. 그 후 yarn dev 를 실행하였더니
yarn install 단계 없이 잘 수행이 되는 것을 확인할 수 있다!!
해결되지 않은 사소한 버그
다만 yarn dev 실행시 node_modules 폴더가 계속 설치되는 것을 확인할 수 있다. PnP 방식을 사용하고 있기 때문에 비록 사용은 안되는 폴더라 크게 상관은 없지만 일단 사용이 안되는 폴더가 만들어진다는 것 자체가 좀 찝찝한 부분이긴 하다. 해당 버그와 관련해서 명확한 해결법을 찾으면 업데이트 해야겠다.
긴 여정이였지만 Vite + Yarn Berry로 마이그레이션에 성공하였다. 이제 좀 쉬자 ㅎ
❗혹시 만약 'Failed to load config "react" to extend from' 오류가 뜬다면
'FrontEnd > React' 카테고리의 다른 글
스토리북(Storybook) 도입하기 (2) | 2024.02.05 |
---|---|
Vite + Yarn berry 프로젝트 배포하기 (0) | 2023.12.24 |
Vite + Yarn Berry 구축기 - 1 (4) | 2023.12.06 |
AWS EC2에 HTTPS 적용하기 (4) | 2023.11.28 |
배포 과정 Github Actions 로 자동화하기 (0) | 2023.11.27 |