node_modules는 많은 파일들이 매우 큰 공간을 차지하고 의존성 검색이 비효율적으로 동작한다. 이를 개선해보고자 yarn berry에 대해 알아보았다.
Yarn Berry는 node_modules를 생성하지 않는다. 대신 .yarn/cache
폴더에 의존성의 정보가 저장되고, .pnp.cjs
파일에 의존성을 찾을 수 있는 정보가 기록된다. .pnp.cjs
를 이용하면 디스크 I/O 없이 어떤 패키지가 어떤 라이브러리에 의존하는지, 각 라이브러리는 어디에 위치하는지를 바로 알 수 있다.
디스크 I/O란
우리가 데이터를 작성 하고 변경 할적에 디스크 즉 HDD 에 그것이 저장되는 것을 말한다.
// .pnp.cjs를 보면 알 수 있다.
/* react 패키지 중에서 */
["react", [
/* npm:17.0.1 버전은 */
["npm:17.0.1", {
/* 이 위치에 있고 */
"packageLocation": "./.yarn/cache/react-npm-17.0.1-98658812fc-a76d86ec97.zip/node_modules/react/",
/* 이 의존성들을 참조한다. */
"packageDependencies": [
["loose-envify", "npm:1.4.0"],
["object-assign", "npm:4.1.1"]
],
}]
]],
특정 패키지와 의존성에 대한 정보가 필요할 때 바로 알 수 있다.
Yarn PnP 시스템에서 각 의존성은 Zip 아카이브로 관리된다. .pnp.cjs
파일이 지정하는 바에 따라 동적으로 Zip 아카이브의 내용이 참조된다.
아카이브란
백업 또는 다른 장소로의 이동시키는 등의 목적을 위해 컴퓨터 파일들을 뭉쳐놓은 모음을 말한다.
Zip 아카이브로 의존성을 관리하면 다음과 같은 장점이 있다.
체크섬이란
데이터에 오류가 있는지 확인하는 데 사용되는 일련의 숫자와 문자이다. 원본 파일의 체크섬을 알고있는 경우 체크섬 유틸리티를 사용하여 복사본이 동일한 지 확인할 수 있다. 네트워크 문제로 인해 파일이 제대로 다운로드되지 않았거나 하드 드라이브 문제로 인해 디스크의 파일이 손상되었을 수 있는데 이때 원본 파일의 체크섬을 알고있는 경우 체크섬 또는 해싱 유틸리티를 실행해서 원본과 동일한 체크섬인지 비교할 수 있다.
.pnp.cjs
파일이 제공하는 자료구조를 이용하여 바로 의존성의 위치를 찾기 때문에 require()에 걸리는 시간이 크게 단축된다..pnp.cjs
파일을 이용하여 관리되기 때문에 더 이상 외부 환경에 영향받지 않는다. CI란
지속적인 통합(Contious Integration)은 운영을 하면서 기능이라든가 개선을 더해가는 방식이다.
유령 의존성
NPM 및 Yarn v1에서는 중복해서 설치되는 node_modules를 아끼기 위해 끌어올리기(Hoisting) 기법을 사용한다. 왼쪽 트리에서 [A (1.0)]과 [B (1.0)] 패키지는 두 번 설치되므로 디스크 공간을 낭비한다. NPM과 Yarn v1에서는 디스크 공간을 아끼기 위해 원래 트리의 모양을 오른쪽 트리처럼 바꾼다. 오른쪽 트리로 의존성 트리가 바뀌면서 package-1 에서는 원래 require() 할 수 없었던 [B (1.0)] 라이브러리를 불러올 수 있게 되었다.직접 의존하고 있지 않은 라이브러리를 require() 할 수 있는데(유령 의존성) 문제는 package.json에 명시하지 않은 라이브러리를 사용할 수 있게 되서 다른 의존성을 package.json에서 제거했을 때 의존성 관리 시스템을 혼란스럽게 만들 수 있다.
설치부터 애를 먹었다. 순서와 활용법을 정확히 인지하지 못한채 발생한 문제이다. 지금은 에러를 해결했지만 다시 에러를 따라서 문제를 찾아보았다.
yarn dlx @yarnpkg/sdks vscode
작업 영역 버전 사용까지 했지만 react 찾을 수 없다는 에러가 발생했다. 하지만 분명 create vite를 할때 react-ts로 생성을 해서 없을리가 없었다고 생각했다. 문제의 원인은 타입스크립트의 버전 허용을 안해줘서이다. 안전상의 이유로 VSCode에서는 yarn의 pnp 모드를 사용할때에 타입스크립트 버전을 명시적으로 활성화 해줘야 한다. 버전 허용을 해주니 에러는 해결 됐다.
pnp를 통한 패키지 설치를 하면 각 디펜던시에 대해 문제되는 부분을 알려준다.
styled-components에서 doesn't provide react-is, requested by styled-components
발생했다. 의존성 모듈로 react-is가 없다는 것이다. styled-components 라이브러리 내에 하위 디펜던시로 react-is를 명시하지 않았다.
yarn berry에서는 확장 설치를 할 수 있는 기능이 yarnrc.yml 파일의 packageExtentions
기능을 통해서 명시해주면 해결이 된다.
packageExtensions:
'styled-components@*':
dependencies:
'react-is': '^18.2.0'
타입스크립트의 버전 허용과 추가 라이브러리의 하위 디펜던시 명시를 주의하면서 해보자.
yarn create vite [폴더명] --template react-ts
yarn set version berry
yarn
yarn dlx @yarnpkg/sdks vscode
// 버전 허용하기
yarn plugin import typescript
여기까지 끝났다면 개발을 시작하면 된다.
yarn berry의 PnP 장점에서 더 나아가 zero-install을 알아본다. 의존성을 Git에서 버전관리를 하는 것이다. PnP는 의존성을 압축 파일로 관리해서 용량이 작다. 그리고 각 의존성은 Zip 파일 하나로 있어서 의존성을 구성하는 파일의 갯수가 많지 않다.
용량이 적고 파일 갯수도 적기 때문에 Git으로 관리가 가능하다. 저장소를 복제하거나 브랜치를 바꿔도 yarn install을 하지 않아도 된다. CI에서 의존성 설치하는 시간이 줄어든다. Git에서 clone을 한다면 바로 사용이 가능하기 때문이다.
.gitignore
에 추가해주자
# Zero-Install을 사용하겠다면?
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Zero-Install을 사용하지 않겠다면?
.yarn/*
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
.pnp.*