drrr은 monorepo를 도입하면서 yarn berry를 사용하게 되었습니다. monorepo를 도입하는 과정에서 yarn berry zero install과 pnp을 통해 패키지를 관리하는 것에 대해 알게 되었습니다.
yarn berry의 zero-install과 PnP를 도입하려 했으나, vitest와의 호환성 문제로 인해 최종적으로 node_modules 방식을 유지하기로 했다
모노레포 프론트엔드 아키텍처로 프로젝트를 세팅하는 과정에서 yarn으 도입하였고, version 1로 세팅 하는 과정에서 다양한 error 또는 version으로 인한 에러가 발생하게 되었습니다.
그래서 이로 인해 Yarn Berry
에 대해 알게 되었으며, 해당 버전을 통해 초기 프로젝트를 세팅하게 되었습니다.
Yarn Berry
는 Yarn
version 2 이상을 가리키는 새로운 Yarn
패키지 매니저입니다.
어떤 프로젝트를 구성하든 의존성은 결정적입니다. Berry
는 node_modules
에 패키지 팡리을 저장하는 대신 패키지의 압축 파일을 ./yarn/cache
폴더에 수평적으로 저장하는 방식으로 위 문제를 해결하였습니다.이 방식을 Yarn
은 PnP
라고 부릅니다. 압축 파일은 ZipFs를 이용하여 해당 모듈 로드가 필요할 때 메모리에서 압축을 해제하여 접근합니다.
빠른 의존성 검색
의존성이 .yarn/cache
에 수평적으로 존재하므로 모든 패키지에 대한 접근 시간이 O(1)
이 됩니다. 따라서 require()
에 소요되는 시간이 크게 단축됩니다.
빠른 설치
압축 파일 단위로 설치되기 때문에 의존성을 구성하는 파일의 수가 절대적으로 감소합니다. 여기에 zero-install 전략을 사용하면 아예 설치 과정을 생략할 수 있습니다.
호이스팅을 사용하지 않기 때문에 의도하지 않은 의존성이 발생하지 않습니다.
하나의 압축 파일들로 의존성을 관리하고 이 파일을 git으로 관리하면 설치 과정을 제거할 수 있는데 이와 같은 전략을 zero-install이라 합니다.
.yarnrc.yml
nodeLinker: "pnp" // pnp(default), pnpm, node_modules 중 설정 가능.
yarn berry
의 기본 설정 값입니다.
.yarnrc.yml
nodeLinker: node-modules
vsc에서 zero-install
를 사용하기 위해서는 아래와 같은 설정도 꼭 필요합니다.
yarn dlx @yarnpkg/sdks vscode
실제 얼마나 큰 차이가 확인하기 위해 yarn
명령어를 통해 2개의 패키지 매니저 다운 시간을 측정해보았습니다.
node_modules
의 경우 yarn
명령어 입력 시 zero-install
보다 2~3분정도 더 걸린것을 확인할 수 있었습니다.
초기 세팅 단계에서도 2~3분이라면 프로젝트가 커짐에 따라 좀 더 많은 시간이 소요될것이라고 예상하였습니다.
yarn berry
에서 pnp
를 이용해보면 예상과는 다르게 정상적으로 동작하지 않고 dependency
관련 에러가 발생합니다.
각 모듈이 pnp
로 사용할 수 있으려면 pnp
방식에 맞게 의존성 관리가 strict하게 세팅되어 있어야 합니다. 그러나 모든 모듈이 pnp
형태에 맞게 호환되어 있는 상태가 아니기 때문에 pnp
를 제대로 사용하기에는 아직 많은 문제가 발생합니다.
이로 인해 yarn
에서도 완전히 strict한 방식 대신, pnp loose
모드를 통해 명시적으로 요구하는 dependency
를 요구하지 않도록 할 수 있습니다.
.yarnrc.yml
pnpMode: loose
그러나 이는 pnp가 정상적으로 동작하는 것을 보장하지 않습니다. 따라서 웬만하면 pnp 모드를 이용하려면 strict 모드로 이용하는 것이 좋습니다.
zero-install
과 pnp
를 이용하여 vitest global
로 설정하는 도중 호환성 문제로 인해 오류가 발생했습니다.
정확하게 원인을 파악하고자 zero-install
에서 node_modules
로 변경하여 프로젝트를 실행한 결과 정상적으로 작동하였습니다.
이를 해결하기 위해 github issue
에서 제시하는 deps.registryNoLoader
를 사용하였지만 해결하지 못하였습니다.
import { defineConfig, configDefaults } from 'vitest/config';
export default defineConfig({
test: {
deps: {
registerNodeLoader: true,
},
globals: true,
environment: 'jsdom',
exclude: [...configDefaults.exclude, 'service/*', 'admin/*', 'component/*'],
},
});
zero-install
을 사용함으로써 패키지를 보다 효율적으로 관리할 수 있습니다. 하지만 위에서 언급하였듯이 pnp
와의 호환성이 완벽하지 못하고 프로젝트 설정에 대한 시간을 너무 많이 사용하여 pnp
대신 node_modules
를 방식을 유지하기로 결정하였습니다.
새로운 기술 도입 자체보다, 프로젝트를 만들어 가는 과정에서 상황에 맞는 기술을 도입이 중요하다는 것을 알게 되었습니다.
참고한 블로그