yarn berry의 이점

January·2022년 10월 19일
0

Frontend

목록 보기
21/31
post-thumbnail

node_modules는 많은 파일들이 매우 큰 공간을 차지하고 의존성 검색이 비효율적으로 동작한다. 이를 개선해보고자 yarn berry에 대해 알아보았다.

yarn berry

Plug’n’Play (PnP)

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 아카이브로 의존성을 관리하면 다음과 같은 장점이 있다.

  1. 더 이상 node_modules 디렉토리 구조를 생성할 필요가 없기 때문에 설치가 신속히 완료된다.
  2. 각 패키지는 버전마다 하나의 Zip 아카이브만을 가지기 때문에 중복해서 설치되지 않는다. 각 Zip 아카이브가 압축되어 있음을 고려할 때, 스토리지 용량을 크게 아낄 수 있다.
    • 실제로 토스팀에서 의존성이 차지하는 크기를 대폭 감축할 수 있었다.
    • 한 서비스의 경우 NPM을 이용했을 때 node_modules 디렉토리가 약 400MB를 차지했지만, Yarn PnP를 사용했을 때 의존성 디렉토리의 크기는 120MB에 불과했다고 한다.
    • 현재 프로젝트에 node_modules를 보면 용량의 크기를 보지않아도 확연히 차이가 난다.
  3. 의존성을 구성하는 파일의 수가 많지 않으므로, 변경 사항을 감지하거나 전체 의존성을 삭제하는 작업이 빠르다.
    • 없는 의존성이나 더 이상 필요 없는 의존성을 쉽게 찾을 수 있다.
    • Zip 파일의 내용이 변경되었을 때에는 체크섬과 비교하여 쉽게 변경 여부를 감지할 수 있다.

체크섬이란
데이터에 오류가 있는지 확인하는 데 사용되는 일련의 숫자와 문자이다. 원본 파일의 체크섬을 알고있는 경우 체크섬 유틸리티를 사용하여 복사본이 동일한 지 확인할 수 있다. 네트워크 문제로 인해 파일이 제대로 다운로드되지 않았거나 하드 드라이브 문제로 인해 디스크의 파일이 손상되었을 수 있는데 이때 원본 파일의 체크섬을 알고있는 경우 체크섬 또는 해싱 유틸리티를 실행해서 원본과 동일한 체크섬인지 비교할 수 있다.

장점

  1. .pnp.cjs 파일이 제공하는 자료구조를 이용하여 바로 의존성의 위치를 찾기 때문에 require()에 걸리는 시간이 크게 단축된다.
  2. 패키지의 모든 의존성은 .pnp.cjs 파일을 이용하여 관리되기 때문에 더 이상 외부 환경에 영향받지 않는다.
  3. 더 이상 설치를 위해 깊은 node_modules 디렉토리를 생성하지 않아도 된다.
  4. Zero-install을 사용하면 대부분 라이브러리를 설치 없이 사용할 수 있다. 이를 이용하면 CI와 같이 반복적으로 의존성 설치 작업이 이루어지는 곳에서 시간을 크게 절약할 수 있게된다.
  5. 각 패키지들은 자신이 package.json에 기술하는 의존성에만 접근할 수 있다. 우연히 작동할 수 있었던 코드들이 보다 엄격히 관리 된다. 이로써 예기치 못한 버그를 쉽게 일으키던 유령 의존성 현상을 근본적으로 막을 수 있다.
  6. node_modules는 올바르게 의존성 설치가 되지 않으면 재설치를 하는데 node_modules 폴더를 검증하기 어려웠기 때문에 전체 재설치를 수행할 때 node_modules 디렉토리 구조를 다시 만드느라 1분 이상의 시간이 허비가 되기도 한다. Yarn PnP에서는 Zip 파일을 이용하여 패키지를 관리하기 때문에 빠진 의존성을 찾거나 의존성 파일이 변경되었음을 찾기 쉽다.(이슈 2번)

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에서 제거했을 때 의존성 관리 시스템을 혼란스럽게 만들 수 있다.

이런 장점과 vite 번들러와 함께 사용할 때에 시너지가 좋을거 같아서 yarn berry를 사용해보려 한다.

issue

설치부터 애를 먹었다. 순서와 활용법을 정확히 인지하지 못한채 발생한 문제이다. 지금은 에러를 해결했지만 다시 에러를 따라서 문제를 찾아보았다.

#1

yarn dlx @yarnpkg/sdks vscode

작업 영역 버전 사용까지 했지만 react 찾을 수 없다는 에러가 발생했다. 하지만 분명 create vite를 할때 react-ts로 생성을 해서 없을리가 없었다고 생각했다. 문제의 원인은 타입스크립트의 버전 허용을 안해줘서이다. 안전상의 이유로 VSCode에서는 yarn의 pnp 모드를 사용할때에 타입스크립트 버전을 명시적으로 활성화 해줘야 한다. 버전 허용을 해주니 에러는 해결 됐다.

#2

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'

에러 없이 시도

타입스크립트의 버전 허용과 추가 라이브러리의 하위 디펜던시 명시를 주의하면서 해보자.

vite 설치

yarn create vite [폴더명] --template react-ts

버전 변경

yarn set version berry

yarn install

yarn

require special configuration for TypeScript

yarn dlx @yarnpkg/sdks vscode

// 버전 허용하기

Automatically adds @types/ packages

yarn plugin import typescript

플러그인-타입스크립트


여기까지 끝났다면 개발을 시작하면 된다.

Zero-Install

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.*

참고

공식 문서 SDKs
공식 문서 packageExtensions
토스 기술블로그
블로그 참고1
블로그 참고2

0개의 댓글