3 분 소요

Yarn2

yarn vs npm

npm의 문제점

  • lock 파일이 없다보니 생기는 패키지의 버저닝/의존 이슈
    • 패키지 설치 순서에 따라서 디바이스, 환경마다 node_modules 트리가 다를 수 있다.
  • 안정성/보안 이슈
    • 패키지가 설치될 때 자동으로 코드와 의존성을 실행할 수 있도록 허용된다.
    • 검증되지 않은 패키지가 포함될 수 있다는 위험성이 존재한다.
  • 패키지가 늘어날수록 성능 저하

yarn

  • yarn.lock 파일 자동생성, checksum을 통해 어느 환경에서든 동일한 패키지를 설치한다.
  • yarn.lock에 있는 패키지를 설치만 한다.
    • 추가적으로 실행되는 코드나 의존성이 없어 안정성이 상대적으로 높다.
  • 병렬 설치로 속도를 높였다.
  • 내부적으로 mutex를 사용 해 다수의 CLI 실행 시 충돌하거나 오염시키지 않도록 방지한다.
  • cache directory를 통한 오프라인 미러링
    • 처음 빌드 할 때 레지스트리에서 다운로드한 파일을 로컬 캐시에 저장한다.
  • left-pad 이슈 방지
    • npm 레지스트리뿐만 아니라 Bower 레지스트리도 확인한다.

기존 패키지 관리의 문제점

1. 거대한 node_modules

Untitled

  • 파일 시스템(node_modules)을 이용하여 의존성을 관리한다.
    • 특정 라이브러리 패키지를 찾기 위해 계속 상위 디렉토리의 폴더를 탐색한다.
      • 결과가 패키지의 상위 디렉터리 환경에 따라 달라질 수 있다.
      • 패키지를 찾지 못하면 readdir, stat과 같은 느린 I/O 호출이 반복된다.
  • node_modules 디렉토리 구조는 매우 큰 용량을 필요로 한다.

2. 유령 의존성 (Phanthom Dependency)

  • npm과 yarn1 에서는 중복해서 설치되는 문제를 해결하기 위해 끌어올리기(hoisting) 기법을 사용한다.

https://user-images.githubusercontent.com/41617388/148636206-55e23abf-c414-44ef-bad7-621ce4f55061.png

  • A(1, 0), B(1, 0) 이 겹친다. 디스크 공간을 아끼기 위해 왼쪽 > 오른쪽 모양으로 바꾼다.
  • 오른쪽으로 바뀌면서 B(1, 0)을 require 할 수 있게 된다.
  • 이렇게 직접 의존하지 않는 라이브러리를 require 할 수 있는 현상을 유령 의존성이라고 한다.
  • package.json에 정의 하지 않은 라이브러리를 조용하게 사용할 수 있지만, 다른 의존성을 제거했을 때 소리없이 같이 사라지기도 한다.
  • 이런 특성은 의존성 관리 시스템을 혼란스럽게 만든다.

Yarn2

  • yarn2 에서는 위의 문제점들을 해결하기 위해 몇 가지 방법을 고안해냈다.

ZipFS (Zip Filesystem)

  • yarn2에서 패키지 설치 시 node_modules 에 디렉터리 구조를 그리는게 아니라,
  • .yarn/cache 하위에 ZIP 파일로 저장된다.
    Untitled 1

  • ex) recoil@0.1.2 > recoil-npm-0.1.2-9a0edbd2b9-c69105dd7d.zip
  • yarn install 실행 시, zip파일을 node_modules 하위에 압축 해제한다.
  • 장점
    • node_modules 디렉토리 구조를 그릴 필요가 없다. > 설치 빨라짐
    • 각 패키지는 버전마다 하나의 zip만 가져서 중복 설치를 방지한다. > 설치 용량 감소
    • zip 파일이 변경되면 checksum으로 비교하여 변경을 감지한다.
      • 의존성을 구성하는 파일의 수가 많지 않으므로, 변경 사항 감지, 삭제 작업이 빠르다.
    • 패키지를 탐색하는데 사용하는 연산들이 감소한다.

Offline-cache

Untitled 2

  • 의존성도 git 등을 이용하여 버전 관리를 하면 어떨까? > 버전 관리에 포함하자!
  • .yarn 디렉토리를 레포지토리에 추가하면, 의존성을 설치할 필요가 없이 레포지토리를 클론해서 바로 쓰면 된다.

Pros

  • 새로 저장소를 복제하거나 브랜치 변경 시 remote registry에서 패키지들을 받아오지 않는다.
    • 여러 환경, 디바이스에서 동일한 패키지 버전이 보장된다. > 유령 의존성 해결
    • 단순 압축 해제만 하기 때문에 CI에서 의존성 설치 시간을 크게 절약 가능하다.
  • npm 서버가 다운 되더라도 zip 파일 압축 해제만 하면 되기 때문에 오프라인에서도 동작 가능하다.

Plug’n’Play (PnP)

a.k.a. Zero Install

  • PnP는 꽂으면 바로 사용할수 있다.. 라는 의미라고 한다.

동작 방법

  • .pnp.cjs 에 의존성을 찾을 수 있는 정보가 map 으로 기록된다.
  • pnp.cjs 파일과 zip 파일을 런타임 시 링크 해준다.
  • ex) 리액트는 .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"]
          ],
        }]
      ]],
    
  • Zero Install이라는 말에 걸맞게 node_modules 폴더가 없다!
  • pull이나 clone시에 패키지를 설치 할 필요 없이 바로 실행 가능하다.
  • 하지만…
    • 호환성 테이블
    • 런타임 시에 node가 import, require 를 사용 할 때마다 .pnp.cjs 를 연결해줘야 하는데, 라이브러리 제공자들이 PnP에서 지원할 수 있도록 제공해줘야 한다.
    • 지원하지 않는 패키지들은 커스텀 플러그인이나,node_modules 플러그인과 함께 사용해야한다.
    • 또한 디버깅이 쉽지 않은 에러들 때문에 호불호가 갈린다.
    • 이러한 리스크 때문에 보통 PnP는 제외하고 적용하는 듯 하다.

기타 yarn2의 새로운 기능들

결론

  • yarn2의 큰 특징은 1. Offline cache, 2. PnP 이다.
  • Offline Cache는 패키지들이 ZIP으로 관리 돼 안정성과 속도 개선의 이점이 있어 적용해봄직 하다.
  • PnP는 아직 지원도 적고 관리가 어려워 보여 도입이 어려울 것 같다.
    • 또한 지원 버전도 낮은 편이 아니라, 기존 프로젝트보다는 새로운 프로젝트에 적용해보는게 좋을 것 같다.
  • pnpm 도 대체제로 많이 언급 되던데 리서치를 좀 더 해봐야겠다.

ref

카테고리:

업데이트: