Devhyun

메뉴

현재 화면 위치

데브현 메인 블로그 포스트

타이틀

당신이 npm install을 사용하지 말아야할 때

2019.08.19
핫한 길다란

아래는 Qiita에 개재된 「あなたがnpm installをしてはいけない時」를 번역한 내용입니다.

다소 의역이 있어 어색한 부분이 있어도 양해 부탁드립니다. 🙉

개요

여러분은 평소에, 무의식적으로 npm install을 사용하실지도 모릅니다.

그러나, npm install에 대해, 오해하고 있는 사람이 많다고 생각합니다.

'언제 npm install은 문제를 일으킬까'에 대해, 설명하기 난감하다면 계속해서 읽어주세요. 많은 개발자가 의식하지 않고 있지만 정말 중요한 사항이라고 생각하고 있습니다.

덧붙여서 npm 4.x 이하의 버전은 본 글의 대상이 아닙니다.

추가 : 강한 어조를 좋아하므로 오해를 일으킬만한 부분이 있어 어러번 수정하였습니다.

참고자료

npm

npm은 패키지 매니저입니다. 패키지 매니저는, 개발에 필요한 패키지(라이브러리 라든가, 플러그인등 다양한 것들)를 관리하기 위한 툴입니다. 모든 사람들이 전부 같은 개발환경을 구현하기 위해서도 중요한 역할을 수행하고 있습니다.

개발을 시작할때, npm init 커맨드에 의해 package.json이 추가됩니다. 이곳에 사용하고있는 패키지 이름과 버전에 대한 정보를 기입하는것의 의미를, 이 글을 읽고계신 분들은 대부분 알고 계실겁니다.

패키지 추가

새롭게, xxx라는 패키지를 추가할때, npm install xxx --save를 실행하면, package.jsondependencies가 갱신됩니다. 동시에, package-lock.json이라는 파일이 추가됩니다. 이번 이야기의 주인공은 이 파일입니다만, 먼저 package.json에 쓰여있는 내용에 애매함을 설명하고 이어가겠습니다.

semantic versioning의 범위지정

xxx의 최신 버전이 1.0.0의 경우, package.jsondependencies에는, 다음과같은 행이 추가됩니다.

"xxx": "^1.0.0"

이것이 의미하는것은, 1.x.x에 해당하는 최신의 버전이라는 의미입니다.

즉, package.json을 사용하여 xxx의 신버전 1.0.1이 공개된 경우 다음에 npm install을 실행한 사람의 개발환경에는 1.0.1의 버전의 xxx가 설치되는 것입니다.

그렇다면, 언제라도 같은 1.0.0xxx를 설치되게끔 하는것에 대해서는 어떻게 생각하시나요?

dependencies의 버전 고정

package.jsondependencies를, "xxx": "1.0.0"으로 하면 확실히 xxx의 버전은 1.0.0이 될것입니다.

하지만, 이는 오해의 소지가 있습니다. 왜냐하면, xxx1.0.0package.json에는 다음과 같은 dependencies가 기재되어 있을 가능성이 높기 떄문입니다.

"yyy": "^1.0.0"

감이 있으신분들은 눈치채셨겠지만, xxx1.0.0npm install하려고 할때, yyy의 새로운 버전이 발표되었을 경우 어떻게 될까요? 어려분은 같은 xxx1.0.0을 설치했다라고 생각할지 모르지만, yyy의 품질에 따라 완전히 다른, 버전이나 취약성이 포함된 버전 1.1.0이 설치될지도 모릅니다.

(덭붙여서 이것은 실사례가 있고, 검증되지 않은 패키지가 작동할 가능성이 충분히 있습니다. 또한 npm의 제약에 따라 릴리즈로부터 72시간이상 지난 경우 기본적으로 삭제/unpublish가 되지 않기 때문에, 버그로서 전세계에서 발견될 가능성도 있습니다.)

이걸로 npm installpackage.json으로, 모든 사람이 완벽히 같은 개발환경을 재현하는것이 불가능하다고 이해하시면 될것 같습니다.

같은 개발환경의 재현

간단하게 같은 개발환경을 재현하려고 하는 경우, 특히 아무런 생각없이, 패키지가 설치된 node_modules 디렉토리를 GIT 리포지토리에 push할 경우, 다른 사람이 pull하면 npm install을 하지 않아도됩니다. 그러나, 프로젝트의 규모가 커지면, node_modules 디렉토리가 무거워집니다. (아래는 제가 좋아하는 사진입니다. 출처)

image

이렇게 무거운것을 리포지토리에 푸쉬한다는건 제정신이 아니겠지만, 앞서 언급한 package-lock.json이라는 것을 통해, 기본적으로는 node_modules디렉토리를 전체를 알 수 있기때문에, node_modules을 푸쉬하는 대신 package-lock.json을 푸쉬하는겁니다.

그렇기에, package-lock.json은 같은 환경을 재현하기 위해 필요한 것으로 리포지토리에 푸쉬하는 편이 좋습니다.

npm install은 package-lock.json을 덮어쓴다

『좋아. package-lock.json이 있어 안심이 된다. npm install을 하면 완전 같은 환경을 만들수 있겠지!』라고 생각하는 사람이 있다면, 그렇게 되지 않을 경우에 대해 고려해볼 필요가 있습니다. 실제로, package-lock.json이 있다고 해도, npm install을 통해 갱신되는 경우가 있습니다. 즉, 같은 개발환경을 구축할때도, npm install을 사용할 수 없는 가능성이 있습니다.

가능성이라는 것은, npm의 버전에 따라 미묘한 npm install의 구동의 차이나, 다양한 유스케이스, 인위적인 미스가 있기때문에, 같은 개발환경 구축이 어렵다는 가능성을 가리키고 있습니다.
역으로, 누군가가 package.json만 수정했다면, package-lock.jsoncommitpush하지 않아, 충돌해결이 어려웠던 경우도 쉽게 나타납니다.

글의 제목에 대한 답변이 나왔지만, 아직 문제 해결 방법에 대해 언급되지 않았기 떄문에 좀더 읽어주세요.

package-lock.json으로 설치한다

완벽하게 같은 환경을 구현하려고 하는 경우, package-lock.json으로 부터 node_modules디렉토리를 구축할 필요가 있습니다. npm install로는 불가능합니다. (주: 절대는 아닙니다.)

npm ci를 사용해봅시다.

상세한 내용에 대해서는 참고자료를 보시면 아시겠지만, npm ci

  1. node_modules 디렉토리를 삭제
  2. package-lock.jsonpackage.json의 정합성 체크
  3. package-lock.json로부터 node_modules을 구성

위와 같은 동작을 하고 있습니다. 또한, npm install처럼 맘대로 package-lock.json을 갱신하는것이 아니라, 같은 node_modules를 구성하는 것이 가능합니다. 드디어, 완전히 같은 환경을 구축하는 것이 가능해졌습니다.

패키지를 설치

이러한 내용을 근거로, 새로운 프로젝트에 참가할 경우에도 package-lock.json이 잘 커밋되어있다면, npm install이 아니라 npm ci를 사용하는 편이 좋습니다. npm ci가 실패한 경우, 위의 사항을 올바르게 팀에게 공유해주세요.

여담입니다만, 일반적으로 ci라고하는 Continuous Integration를 가르키고 있지만, 동작 측면에서는 Clean Install약어 일지도 모르겠네요. (개인적인 생각입니다)

패키지의 업데이트 & 추가

문서에 나와있는것 처럼 npm cipackage-lock.json을 갱신하지 않고, 개별적으로 패키지를 설치하는것도 불가능합니다.

그러므로, 버전을 업데이트하고 싶은 경우에도, package-lock.json을 갱신하는 것이 가능한 npm install이나 npm update등을 사용합니다. 또한, 패키지를 추가하고 싶을 때도 지금과 마찬가지로 npm install zzz --save를 사용하면 괜찮습니다. 단, 이때 package-lock.json이 갱신되면 반드시 변경된부분이나 동작에 문제가 없는지 확인하고, 리포지토리에 push, 팀맴버에게 npm ci의 실행을 알려주는게 베스트입니다.

상상력이 풍부한 사람이라고 하면, 이 npm install에 의해 의존 패키지 하위의 의존패키지...가 버그를 포함한 갱신을 한 경우, 어떻게 대처하면 좋을지 생각하신 분도 계실겁니다.

의존 패키지의 하위의 의존 패키지를 고정하는 방법

사실 npm에는 이런 기능이 없습니다. (있다면 알려주세요.)

그렇지만, yarn에는 있습니다. package.jsonresolutions이라는 필드를 추가하여, 그곳에 패키지의 버전을 지정하는것으로 의존 라이브러리의 하위의 의존 라이브러리의 버전을 지정할수 있습니다.
(여기를 참고해주세요.)

마치며

이와 관련하여 보안적인 관점에서 말하자면, 이해가 얕고 대비책이 없는 프로젝트의 경우, 그 프로젝트에서 사용되고 있는 라이브러리 소스코드에 악의적인 코드를 끼워넣은 배치버전 릴리즈 같은걸 한다면, 다음번에 배포될때 바이러스에 감염될 가능성도 있겠네요.

꼭 현재 개발 프로세스를 다시 한번 확인해주세요. !

0개의 댓글

로그인을 하시면 댓글을 작성할 수 있어요 !
목록으로 가기