개발

자바스크립트 패키지 매니저란?

dohye1 2022. 9. 26. 00:24
반응형

패키지 매니저란?

  • 패키지 매니저는 패키지를 다루는 작업을 편리하고 안전하게 수행하기 위해 사용되는 툴이다.
  • 패키지 매니저의 도움으로 패키지를 설치, 제거, 업데이트 및 업그레이드하고, 프로젝트 설정을 구성하고, 스크립트를 실행하는 등의 작업을 수행할 수 있다.
  • 대부분의 자바스크립트 패키지 매니저는 Node.js 실행 환경(runtime)에서 돌아가며 package.json이라는 파일에 프로젝트가 의존하고 있는 패키지 목록을 명시한다. 

패키지란?

  • 라이브러리가 코드의 작성을 위해 사용되는 코드의 묶음이라면, 패키지는 코드의 배포를 위해 사용되는 코드의 묶음이다.

패키지 매니저가 하는일

  1. 패키지의 dependency 관리
  2. 패키지의 보안관리 ㅡ 신뢰할 수 있고(authenticity), 손상되지 않음(integrity)을 보장
  3. 여러 패키지를 기능에 따라 그룹으로 묶어 정리
  4. 패키지 압축 해제
  5. Software repository로부터 패키지를 찾고, 다운로드하고, 설치하고, 업데이트하는 역할
Software repository란 패키지를 저장하고 관리하는 저장소이다.
원격저장소라고 생각하면 될듯! 내가 npm install이나 yarn add를 실행하면 원격저장소에서 다운받게됨

NPM

  • 자바스크립트 언어를 위한 패키지 관리자로, Node.js의 기본 패키지 관리자이다.

1. NPM은 파일시스템을 이용해서 의존성을 관리한다.

파일 시스템이란?
파일 시스템은 파일을 포함하도록 할당된 하드 디스크의 한 구역입니다.
디렉토리에 파일 시스템을 마운트하여 이 구역에 액세스합니다.
파일 시스템이 마운트된 후에는 이 구역이 일반 디렉토리와 똑같습니다.

  • 만약 require()를 사용해서 특정 패키지를 불러올때, Node.js에서 제공하는 require.resolve() 함수를 사용한다.
  • require.resolve() 함수는 NPM이 검색하는 디렉토리를 반환하는데, 그 예시를보면 아래와 같다.

  • 쉽게 말하자면 js파일에서 require나 import를 사용해서 모듈을 읽어오려고 하면, node는 타겟 모듈을 내 컴퓨터의 디렉토리에서 찾는다
  • npm은 패키지를 찾지못하면 상위 디렉터리의 node_modules 폴더를 계속 검색하기때문에, 패키지를 찾을때까지 I/O호출이 반복된다.
  • 그래서 의존성 검색이 때로는 비효율적으로 동작할지도 모른다.

2. 어떤 의존성을 찾을 수 있는지는 해당 패키지의 디렉터리 환경에 따라 달라질 수 있다.

  • 디렉토리가 어떤 node_modules를 포함하고있는지에 따라 의존성을 불러 올 수 있기도 하고, 없기도한다. 그리고, 다른버전의 의존성을 잘못 불러올 수 있는 여지도 존재한다

예시

npm install moment-timezone

 

위 코드를 실행해보면, node_module에는 moment-timezone과 moment가 추가가 된다.

왜냐하면 moment-timezone에서 moment를 사용하기때문에 같이 설치가 되는것이다.

그리고 나서는, js 파일에서 moment를 require해서 사용해보면 잘 실행이된다!

나는 moment를 따로 설치하지않았음에도 사용할 수 있게되었다.

왜냐하면 node의 기본 패키지매니저는 npm이고, npm은 파일시스템을 이용해서 의존성을 관리하기때문에 node_module에 있는 moment에 접근이 가능하게되는것이다.

 

이건 아래에 나오는 유령 의존성문제에서 다시 다룬다.

Yarn v1(classic)

  • 페이스북에서 만든 자바스크립트 패키지 매니저
  • yarn.lock 파일 생성
  • 프로젝트마다 다른 버전의 yarn 사용할 수 있다.
  • yarn은 성능 및 보안문제와같은 npm의 단점을 보완하기위해 나왔다. (그런데 지금은 npm이 각성해서 두개의 격차가 줄었다고한다.)
  • 속도(performance)
    • Yarn은 패키지를 병렬로 설치하는데 이것이 npm보다 빠른 이유 중 하나이다.
    • npm에서 이러한 작업은 패키지별로 순차적으로 실행된다. 즉, 다음 작업으로 이동하기 전에 패키지가 완전히 설치될 때까지 대기하게되는것이다.
  • 안정성(stability)
    • yarn.lock은 모든 디바이스에 같은 패키지를 설치하는 것을 보장하기 때문에 버전의 차이로 인해 생기는 버그를 방지해줄 수 있다.
    • yarn이 출시되는 시점엔 npm은 lock파일이 없었음!
    • 지금은 npm도 lock파일을 생성해준다. 아래의 history를 보면 npm은 version 5부터 package-lock.json을 제공했다는것을 알 수 있다.

그럼 yarn.lock파일과 package-lock.json은 어떤 역할을 하는걸까?

우선 package.json를 먼저 보자!

package.json

  • 우리가 어떤 패키지(오픈소스)를 사용하는지, 어떤 버전을 사용하는지 등을 기록함으로써 어느 곳에서도 동일한 개발 환경을 구축할 수 있게 해준다.
  • package.json을 보면 의존성과 그 의존성에대한 버전정보가 적혀있는것을 볼수있는데, 자세히 들여다보면 특정 버전이 적혀있는것이 아니라, 버전 범위가 적혀있다는것을 확인할 수 있다. (carot^, tilde~)

  • ~version은 patch버전까지의 업데이트를 허용한다.
  • ^version은 minor버전까지의 업데이트를 허용한다.

여기서 발생할 수 있는 문제를 간단하게 얘기해보자면,

만약 A와 B가 하나의 프로젝트로 협업을 하고있을때, 두사람은 동일한 package.json을 공유하고있을것이다.

만약 A가 먼저 의존성들을 설치하고나서, B가 그 이후시점에 의존성들을 설치했다고 하자

그렇게되면 A가 의존성을 설치한시점과, B가 의존성을 설치한 시점 사이에 몇몇개의 라이브러리의 버전이 올라갔다면

두 사람의 node_module에는 동일모듈에대해 다른버전의 코드가 들어있을수도 있게 되는것이다.

 

그럼 두사람은 동일한 환경에서 작업을한다고 할 수 없게 되는것이다.

 

(근데 이건 나혼자 예측한거라 잘못된 예시일수도있음. 잘못되었다면 댓글남겨주세영~)

그래서 이러한 문제를 lock파일을 사용해 해결하고자 한것이다.

 

그럼 아래의 설명이 이해가되시겠찌용?

  • 패키지 버전 불일치를 방지하기 위해 설치된 정확한 버전이 패키지 잠금 파일에 고정되어 있다.
  • 모듈이 추가될 때마다 npm과 Yarn은 각각 package-lock.json및 yarn.lock파일을 생성(또는 업데이트)한다.
  • 허용된 버전 범위를 유지하면서 다른 시스템이 정확히 동일한 패키지를 설치하도록 보장할 수 있다.

 

유령 의존성 (Phantom Dependency) : node_modules

  • npm 및 yarn v1은 중복해서 설치되는 node_moduels를 보완하기 위해서, 의존성들에 대해 hoisting 기법을 사용한다. (hoisting은 코드가 실행하기 전 변수선언/함수선언 이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상을 말한다.)
  • 왼쪽 트리에서 A와 B는 두번 설치되므로 디스크공간을 낭비한다. 그래서 npm과 yarn 1은 디스크공간을 아끼기위해 원래 트리모양을 오른쪽트리처럼 바꾼다.

아까 위에서 언급했었던 moment-timezone을 설치하는 예시를 생각해보면,

moment-timezone은 A(1.0)이고 moment를 B(1.0)이라고 생각하면 이해가 쉬울것이다.

moment는 moment-timezone 폴더안에 있는게아니라, moment-timezone과 같은 레벨로 추가된다.

  • 그래서 직접적으로 의존성이없는 라이브러리를 import해서 사용할수 있게되는데, 이를 유령 의존성이라고 한다. 즉, package.json에 명시하지않은 라이브러리를 사용할수있게 되는것이다.
  • package.json에 명시되지않는 라이브러리를 사용하게되면, package.json에서 dependency를 삭제/업데이트 할때 어떤 사이드이펙트가 발생할지 모른다.
  • 내가 moment를 설치하지않고, moment-timezone을 설치한 다음, moment를 쓰고있었는데, moment-timezone을 지워버리면 moment도 지워지니깐 moment를 쓰고있던 곳에서는 에러가나게된다!

yarn berry는 유령 의존성문제를 Plug’n’Play 전략을 이용해서 해결한다.

yarn v2~(yarn berry)

  • yarn 패키지 매니저의 2번째 버전이다.
  • yarn v1과는 따로 관리된다.
  • 아래의 이미지는 yarn v1 github에서 캡쳐한 이미지인데, yarn v1은 더이상 유지보수가 이루어지지않는다.

yarn berry의 특징을 살펴보자

Plug’n’Play (PnP)

  • Yarn berry는 node_modules를 생성하지 않는다. (옵션 설정에 따라서 node_modules를 설치하도록 할 수 있음)
  • .yarn/cache 폴더에 패키지, 라이브러리를 zip파일로 저장하고, .pnp.cjs파일에 의존성 정보를 찾을 수 있는 정보가 기록된다.

위 이미지에서 볼 수 있듯이, 패키지 이름과 패키지 버전정보를 가진 이름의 zip파일로 추가가된것을 알 수 있다.

위의 예시는 yarn add react를 실행한 결과이고 react가 loose-envify를 사용하기때문에 같이 설치된것을 확인할 수 있다. (js-tokens는 loose-envify에서 사용하는거임)

  • .pnp.js: dependencies들을 찾을 수 있는 정보가 기록된다. 디스크 I/O 없이 어떤 패키지가 어떤 라이브러리에 의존하는지, 각 라이브러리는 어디에 위치하는지를 바로 알 수 있다.

  • 패키지 이름 + 패키지 버전 + 패키지의 실제 위치 + 패키지의 종속성을 담은 맵 형태의 데이터들의 나열이다.
  • 특정 패키지와 의존성에 대한 정보가 필요할 때 바로 알수있다.
  • .pnp.js를 활용하여 기존 방식보다 훨씬 빠르게 애플리케이션의 패키지들을 설치 및 실행할 수 있다.
  • 모든 패키지들이 명시되어있기때문에, 각 패키지들도 최상단으로 끌어올려져서 완전히 플랫한 구조를 갖는다.
  • 그리고 js파일에서 내가 설치하지않은 모듈을 require하거나 import하고나서 yarn node를 실행해보면 해당 모듈을 설치하지않았다고 에러가 뜬다.
  • 모듈을 import 할 때 파일시스템이 아닌, pnp.js에서 정보를 읽기때문에 그런것같다! pnp.js에는 내가 직접 설치한 모듈정보도 나열되어있음

ZipFS (Zip FileSystem)

  • Yarn PnP시스템에서 의존성은 Zip으로 관리된다.
  • Zip으로 의존성을 관리했을때의 장점
    • 각 패키지는 버전마다 하나의 Zip 아카이브만을 가지기 때문에 중복해서 설치되지 않는다.
    • 각 Zip 아카이브가 압축되어 있기때문에, 스토리지 용량을 아낄수있다.

Zero-install

  • 그러니깐 이제 node_modules를 .gitignore에 추가할 필요가없게되는거임!(왜냐하면 pnp전략을 사용하게되면 node_modules자체가 생성되지않으니깐!)
  • 그리고 zip파일의 용량이 작기때문에 .yarn/cache 폴더 자체를 github이나 gitlab같은 코드 원격 저장소에 그대로 올려도 된다. 

압축하기 전 moment-timezone의 용량
압축한 후의 moment-timezone의 용량

  • 그래서 내가 올린 코드를 다른사람이 로컬에 받아서 실행할때 npm install이나 yarn add 를 따로 할 필요없이, 바로 실행이 가능하다.

정리하자면

  • 용량과 파일의 숫자가 적기때문에 Yarn Berry를 사용하면 의존성을 git으로 관리할 수 있다.
  • 다른 환경에서도 별도의 yarn install을 통한 설치가 필요없도록 repository에 commit을 하도록 요구함.
  • Zero-Installs을 사용하면 반복적으로 의존성 설치 작업이 이루어지는 CI 단계에서 시간을 단축할 수 있다.

그런데 찾다보니 pnpm이라는것도있넹..?

이것도 추가해야될듯

10월안에 추가안하면 나 진짜 빵꾸똥꾸임

참고

자바스크립트 패키지 관리자의 역사 < 이 글이 정리가 꼼꼼히 되어있는듯

node_modules로부터 우리를 구원해 줄 Yarn Berry

Yarn Berry를 사용해보자

Yarn vs npm: Everything You Need to Know - SitePoint

https://aahc.tistory.com/14