Skip to main content

Command Palette

Search for a command to run...

[ 살펴보기 ] NPM - Files, Config, Dependency

Updated
4 min readView as Markdown
[ 살펴보기 ] NPM - Files, Config, Dependency
C

A developer living in Busan, Korea

NPM이 congifuration을 위해 어떤 파일을 사용하는지 그리고 system의 어떤 folder에서 어떤 file을 관리하는지 살펴보자.

Folders and files

NPM을 통해 package를 설치할 시 현재 project의 node_modules에 package를 설치하고 만약 global로 package를 설치시 package는 node가 설치된 위치에 있는 node_modules에 설치된다.

만약 nvm을 통해 node version을 관리중이라면 nvm이 설치된 경로에 존재하는 각 node version 폴더 안에 있는 node_modules에서 global package가 관리된다. 여러 version을 설치해서 사용중이라면 global package가 실제로 설치되는 위치는 현재 사용중인 node version의 node_modules에 설치된다.

Npm cache file은 %LocalAppData%/npm-cache 경로에 위치한다. ( Window일 경우 ) Npm install을 통해 package를 설치할 경우 package는 cache 폴더에 download 되고 npm install을 실행했던 project의 node_modules에 unpack된다.

이 때 설치한 package에 executable 파일이 있으면 node_modules/.bin 경로에 symlink를 만들고 이를 통해 executable command를 npm script로 실행할 수 있게 된다. ( NPM - More infomation )

예를들어 rollup이라는 package를 local로 설치하면 해당 package의 executable 파일의 위치는 rollup package package.json에서 확인 할 수 있다.

 {
  ...
  "bin": {
    "rollup": "dist/bin/rollup"
  }
}

executable file의 위치가 dist/bin/rollup이므로 rollup의 executable command를 실행하려면 다음과 같이 할 수 있을 것이다. ./node_modules/rollup/dist/bin/rollup main.js --file bundle.js

하지만 package를 설치하면 npm에서 node_modules/.bin 폴더에 symlink를 생성해주기 때문에 다음의 명령어로도 package의 executable을 실행할 수 있다.

./node_modules/.bin/rollup main.js --file bundle.js

즉, package 설치 시 생성되는 symlink를 통해 아래와 같이 작업중인 project의 pakcage.json에 npm script를 추가하여 특정 package의 executable을 실행할 수 있게 된다. 아래의 예제의 npm script 실행결과는 ./node_modules/.bin/rollup main.js --file bundle.js의 실행결과와 같다.

{
  ...
  "scripts": {
    "rollup": "rollup main.js --file bundle.js",
  }
}

Javascript는 Interpreted language이기에 Executable 파일도 machine code가 아닌 Javasciprt code다. 명령어를 통해 특정 Package의 Executable command가 실행되면 NodeJS ( V8 Engine )가 Executable 파일을 해석하고 실행한다.

모든 npm package가 executable 파일을 포함하고 있지는 않으니 주의하자.

Configuration

Npm command를 실행할 때 configuration option을 설정할 수 있는 방법은 다양하다. command를 실행 할 때 flag옵션을 추가 해주거나 혹은 환경변수로 설정해주거나 혹은 .npmrc 파일에 configuration 옵션을 설정할 수 있다.

Configuration을 적용할 때 우선순위는 command line flag > 환경변수 > .npmrc 순서로 높다.

.npmrc를 통해 npm configuration을 설정 할 때 수정하는 .npmrc 파일의 위치에 따라 현재 OS에 접속한 user level에서 변경할 수도 있고 아니면 현재 작업중인 프로젝트 level에서 특정 configuration을 적용할 수도 있다.

만약 project 단위로 특정 npm configuration을 적용하고 싶다면 proejct root에 .npmrc 파일을 생성해 원하는 configuration 값을 설정해준다. 혹은 현재 OS에 접속한 user level로 변경하고 싶다면 접속한 user의 home directory의 .npmrc 파일을 수정해준다.

예를들어 현재 작업중인 project에서 npm package를 install할 때 timout되는 최대 시간을 조정하고 싶다면 project root에 .npmrc 파일을 생성하고 다음과 같이 설정해준다.

fetch-timeout=100000

이후 npm config list 명령어를 실행해보면 위의 configuration이 적용된 것을 확인할 수 있다.

Configuration에 사용할 수 있는 option은 굉장히 많으므로 documentation을 참고하자.

Dependency Hoisting

만약 package dependency graph가 다음과 같다고 가정해보자.

a -> b -> c -> b -> c

여기서 b package는 c package에 의존하고 c pakcage는 다시 b package에 의존한다. 위와 같은 상황에서 제일 하단에 위치한 c package는 자신의 node_modules에 b를 한번 더 설치하지 않고 a/node_modules에 설치된 b를 그대로 사용한다.

즉, 상단의 node_modules에 이미 동일한 package가 존재한다면 새로 설치하지 않고 이미 설치된 package를 사용한다. 다만 이는 서로 설치하는 package가 동일한 버전일 때 한정이다.

만약 a/node_modules의 b pacakge가 3 version 이고 c가 필요로 하는 b package의 version이 2라면 c package은 a에서 이미 설치된 b가 아닌 자신의 node_modules에 2 version의 b를 설치하여 사용한다.

NPM은 package의 중복 설치를 막기 위한 또 다른 수단으로 package를 설치할 때 node_modules 안에서 package가 설치되는 위치를 끌어올리는 hoisting을 적용한다.

만약 다음과 같은 dependency graphy가 있다고 가정해보자. 아래는 NPM Documentation에서 Hositing 과정을 설명하기 위해 사용하고 있는 예제다.

foo
+-- blerg@1.2.5
+-- bar@1.2.3
|   +-- blerg@1.x (latest=1.3.7)
|   +-- baz@2.x
|   |   `-- quux@3.x
|   |       `-- bar@1.2.3 (cycle)
|   `-- asdf@*
`-- baz@1.2.3
    `-- quux@3.x
        `-- bar

만약 dependency graph가 위와 같을 때 NPM은 package의 중복 설치를 피하기 위해 다음과 같이 일부 package를 hoist 시킨다.

foo
+-- node_modules
    +-- blerg (1.2.5) <---[A]
    +-- bar (1.2.3) <---[B]
    |   +-- node_modules
    |       +-- baz (2.0.2) <---[C]
    +-- asdf (2.3.4)
    +-- baz (1.2.3) <---[D]
    +-- quux (3.2.0) <---[E]

우선 bar@1.2.3, baz@1.2.3, blerg@1.2.5는 foo/node_modules로 설치된다. 그리고 bar@1.2.3blerg@1.x을 의존성으로 가지고 있지만 foo/node_modules에 설치된 blerg@1.2.5가 해당 의존성의 요구사항을 충족하므로 새로 설치되지 않는다.

하지만 [ B ]에 위치한 bar@1.2.3의 의존성은 baz@2.0.2이므로 foo/node_modules에 설치된 baz@1.2.3를 사용할 수 없다. 그러므로 [ B ]에 위치한 bar@1.2.3baz@2.0.2를 자신의 의존성으로 node_modules에 설치한다.

이런식으로 상단에 이미 설치된 package가 있다면 같은 package를 중복 설치하지 않고 이미 설치된 package를 재사용하기 위해 NPM은 package를 top-level로 끌어올린다. bar@1.2.3의 의존성이였던 asdfbaz@1.2.3의 의존성이였던 quux@3.x package 역시 top-level로 끌어 올려진 것을 확인할 수 있다.

이로인해 baz@1.2.3baz@2.x에서 quux@3.x를 중복 설치하지 않고 foo/node_modules로 hoist된 quux@3.x를 재사용한다.

More from this blog

[ 살펴보기 ] TypeORM - Transactions, Migration

Transation Database 종류에 따라 detail한 부분은 차이점이 조금씩 있겠지만 각 sql statement는 개별적인 transaction block을 통해 실행되며 Database 설정에 따라 sql statement의 실행 결과가 자동으로 commit되어 영구히 적용되거나 commit을 직접 실행하기 전까지는 영구히 적용되지 않을 수 있다. 대부분의 경우 default로 sql statement 실행 결과가 자동으로 comm...

Feb 9, 20256 min read
[ 살펴보기 ] TypeORM - Transactions, Migration

Dev Diary

184 posts