[node.js] npm이 사용하는 폴더 구조

원문: https://docs.npmjs.com/cli/v8/configuring-npm/folders

번역: 양정석 (dasomoli@gmailREMOVETHIS.com)

설명

npm은 여러분의 컴퓨터 상에 다양한 것들을 둡니다. 이게 그게 하는 일이예요.

이 문서는 이게 어디에 무엇을 두는지 설명합니다.

요약

  • 로컬 설치 (기본): 현재 패키지의 루트 디렉토리의 ./node_modules 에 설치
  • 글로벌 설치 (-g 옵션): /usr/local 또는 노드가 설치된 곳에 설치
  • require()를 한다면 로컬에 설치
  • 커맨드 라인에서 실행한다면 글로벌 설치
  • 로컬과 글로벌 둘 다 필요하다면 양쪽 모두에 설치하거나 npm link를 사용

prefix 설정

기본 prefix 설정은 노드가 설치된 곳입니다. 대부분 /usr/local 입니다. 윈도우즈에서는 %AppData%\npm 입니다. {prefix}/node.exe 가 아니라 {prefix}/bin/node에 보통 설치되므로 유닉스 시스템에서는 한 레벨 더 들어갑니다.

global 플래그가 설정되면, npm은 이 prefix 내에 설치합니다. 설정되지 않았다면, 패키지 내에 없으면 현재 패키지 또는 현재 작업 디렉토리의 루트 디렉토리를 사용합니다.

노드 모듈

패키지들은 prefix 아래의 node_modules 폴더 내에 들어갑니다. 로컬에 설치될 때, 이는 main 모듈을 로드하기 위해 여러분이 require("packagename")을 사용하거나 다른 모듈을 사용하기 위해서 require("packagename/lib/path/to/sub/module")을 사용할 수 있다는 뜻입니다.

유닉스 시스템 상에서의 글로벌 설치는 {prefix}/lib/node_modules로 진행됩니다. 윈도우즈 상에서 글로벌 설치는 {prefix}/node_modules로 진행(즉, lib가 없음)됩니다.

범위가 지정된 패키지들은 @ 기호가 붙는 범위 prefix의 이름과 연관된 node_modules 폴더의 하위 폴더 내에 함께 그룹지어지는 것을 빼면 같은 방식으로 설치됩니다. 예를 들어, npm install @myorg/package는 그 패키지를 {prefix}/node_modules/@myorg/package 내에 설치합니다. 더 자세한 사항은 scope을 참고하세요.

패키지를 require()하길 원한다면, 로컬에 설치하세요.

실행 파일

글로벌 모드에서 유닉스 상에서는 {prefix}/bin, 윈도우즈 상에서는 {prefix}에 직접 실행 파일이 링크됩니다. 여러분의 터미널의 PATH 환경 변수에 이를 실행할 수 있도록 이 경로가 들어가 있는지 꼭 확인하세요.

로컬 모드에서 실행파일은 ./node_modules/.bin 내에 링크되기 때문에 npm을 통해 스크립트 실행이 가능합니다. (예를 들어 npm test를 실행할 때 그 경로 내에 테스트 러너가 있을 겁니다)

Man Pages

글로벌 모드에서 man page는 {prefix}/share/man 내로 링크됩니다.

로컬 모드에서는 man page는 설치되지 않습니다.

Man page는 윈도우즈 시스템 상에서 설치되지 않습니다.

캐시

npm cache를 보세요. 캐시 파일들은 Posix 상에서는 ~/.npm 내에, 윈도우즈 상에서는 %AppData%/npm-cache 내에 저장됩니다.

이는 cache 설정 파라미터에 의해 제어됩니다.

임시 파일

임시 파일은 기본 값인 TMPDIR, TMP, TEMP 환경변수, 또는 유닉스 상에서 /tmp나 윈도우즈 상에서 c:\windows\temptmp 설정으로 지정된 폴더 내에 저장됩니다.

임시 파일들은 이 루트 디렉토리 안에 프로그램의 각각의 실행에 대한 유일한 폴더가 지정되고, 성공적으로 끝나면 지워집니다.

더 자세한 정보

로컬 설치 시에 npm은 먼저 적절한 prefix 폴더를 찾으려고 시도합니다. 이는 그래서 npm install foo@1.2.3은 여러분이 다른 폴더로 cd를 이용해서 이동했었다 하더라도 여러분의 패키지의 합리적인 루트 디렉토리에 설치할 겁니다.

$PWD에서 시작해서 npm은 package.json 파일 아니면 node_modules 폴더를 갖는 폴더를 확인하면서 탐색합니다. 그런 것을 찾으면 npm 명령을 실행하는 목적에 맞는 실제적인 “현재 디렉토리”로 취급합니다. (이 동작은 git의 작업 디렉토리 내에서 git 명령을 실행했을 때 .git 폴더를 찾는 로직에서 영감을 받아 비슷합니다).

아무 패키지 루트도 찾지 못했다면, 현재 폴더가 사용됩니다.

npm install foo@1.2.3을 실행하면, 그 패키지는 캐시 내에 로드된 후, ./node_modules/foo내에 풀게 됩니다. 그 후 foo의 디펜던시들은 비슷하게 ./node_modules/foo/node_modules/...에 풀게 됩니다.

./node_modules/.bin에 심볼릭 링크된 바이너리 파일들은 npm 스크립트가 필요할 때 찾을 수 있습니다.

글로벌 설치

global 설정이 true로 설정되면, npm은 “글로벌”로 패키지를 설치합니다.

글로벌 설치에서 패키지들은 위에서 설명된 폴더를 사용해서 거의 같은 방식으로 설치됩니다.

순환, 충돌, 그리고 폴더의 중복 제거

순환은 node_modules 폴더를 찾는 디렉토리를 탐색하는 노드의 모듈 시스템 속성을 사용해서 처리됩니다.모든 단계에서 어느 패키지가 이미 그 상위의 node_modules 폴더에 설치되어 있다면 현재 위치에는 설치하지 않습니다.

foo -> bar -> baz에서 위의 경우를 생각해 봅시다. baz가 bar에 의존한다고 상상해보면, foo -> bar -> baz -> bar -> baz ... 가 될 겁니다. 그러나 폴더 구조가 foo/node_modules/bar/node_modules/baz가 되기 때문에 require("bar")를 부르면, foo/node_modules/bar 내에 설치된 복사본을 얻을 것이므로 bar의 다른 복사본을 .../baz/node_modules 내에 둘 필요가 없습니다.

이 손쉬운 방법은 정확히 같은 버전이 중첩된 node_modules 폴더 내에 설치되었을 때만 사용됩니다. 두 “a” 패키지가 다른 버전이라면 a/node_modules/b/node_modules/a가 되는 것이 여전히 가능합니다. 그러나 정확히 같은 패키지를 여러번 반복하는 일 없이 무한 회귀는 언제나 방지됩니다.

다른 최적화는 아래의 로컬라이즈된 “target” 폴더 아래에 가능한 한 가장 높은 레벨에 의존 모듈들을 설치해서 구성할 수 있습니다.

예제

이런 의존 그래프를 생각해보죠.

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 (순환)
|   `-- asdf@*
`-- baz@1.2.3
    `-- quux@3.x
        `-- bar

이 경우, 우리는 다음과 같은 폴더 구조를 기대할 수 있을 겁니다.

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

foo가 bar@1.2.3baz@1.2.3에 직접 의존하므로, 이들은 foo의 node_modules 폴더 내에 설치됩니다.

blerg의 최신본이 1.3.7임에도 불구하고, foo는 1.2.5 버전으로 지정된 의존을 갖습니다. 그래서 이는 [A]에 설치됩니다. blerg의 상위 설치가 bar의 blerg@1.x 의존을 만족하므로, [B] 아래에 다른 복사본을 설치하지 않습니다.

bar [B] 또한 baz와 asdf에 의존을 갖습니다. 그래서 이들은 bar의 node_modules 폴더에 설치됩니다. 이게 baz@2.x에 의존하므로 그 상위의 node_modules 폴더 [D] 에 설치된 baz@1.2.3을 재사용할 수는 없고, 그 자신의 복사본 [C]를 설치해야만 합니다.

bar 아래에 baz -> quux -> bar 의존은 순환을 만듭니다. 그러나 bar가 이미 quux의 조상 [B] 이므로, 그 폴더 내에 bar의 다른 복사본을 풀지 않습니다.

foo -> baz [D] 아래에, quux의 [E] 폴더 트리는 비게 됩니다. bar 상의 그 의존이 [B] 에 설치된 상위 폴더 복사본에 의해 만족되기 때문입니다.

무엇이 어디에 설치되는지의 그래프 분석은 npm ls를 사용하세요.

퍼블리싱

퍼블리싱 상에서 npm은 node_modules 폴더 안을 들여다 봅니다. 항목 들 중 어느 것도 bundledDependencies 배열에 들어있지 않으면, 그들은 패키지 tarball 내에 포함되지 않을 겁니다.

이는 패키지 메인테이너가 그들의 의존 모두를 로컬에 설치할 수 있도록 하지만, 다른 곳에서 찾을 수 없는 이들 항목만 다시 퍼블리싱 합니다. 더 자세한 정보는 package.json을 보세요.

더 읽을 거리

[WordPress] 워드프레스 플러그인 수동 설치/업데이트

ftp 서버로 WordPress가 설치된 디렉토리의 권한을 주기 어려운 경우, 혹은 ssh에 딸린 sftp 외에 ftp 운영을 하고 싶지 않은 경우, 수동으로 플러그인을 설치해주어야 한다.

WordPress plugin을 manual로 설치하려면, wordpress plugin 페이지에서 해당 플러그인의 zip 파일을 받아서 자신의 WordPress 디렉토리에서 wp-content/plugins/ 아래로 복사한 후 압축을 해제하면 된다.

예를 들어, akismet을 수동으로 설치하고 싶다면, https://ko.wordpress.org/plugins/akismet/ 에 접속해서 다운로드 버튼을 눌러 최신 akismet.4.1.6.zip 과 같은 파일을 받아 sftp등으로 wp-content/plugins/ 아래에 업로드 한 후, 쉘에서 압축을 unzip 등으로 풀어주면 된다. 플러그인 zip 파일의 경우 풀면 해당 플러그인 디렉토리 명으로 압축이 해제된다.

이후 관리자 페이지에 접속한 후, 플러그인을 보면 압축을 푼 플러그인이 보인다. 활성화를 눌러 주면 된다.

 

moniwiki 설치

글 정리할 때 익숙한 건 역시 moniwiki다. 다시 설치하려니 github로 옮겨가고, wikiseed 심는 것도 따로 프로젝트를 따로 뒀던데 다시 설치하는 절차를 정리한다.

설치하려는 디렉토리 아래(난 /var/www/)에서 git clone

[code]
git clone https://github.com/wkpark/moniwiki.git
chown -R www-data:www-data moniwiki
cd moniwiki/
git clone https://github.com/wkpark/moniwiki-wikiseed.git wikiseed
cd theme/
git clone https://github.com/wkpark/moniwiki-theme-paper.git paper
git clone https://github.com/wkpark/moniwiki-theme-bootstrap3.git bootstrap3
git clone https://github.com/wkpark/moniwiki-theme-publish.git publish
[/code]

브라우저에서 monisetup.php 접속

  1.  $sitename 설정
  2.  $admin_passwd 설정
  3.  $use_sectionedit 설정
  4.  “Sow wikiseed” 로 wiki seed 심기

추가로 config.php 에서 고치기

http://blog.dasomoli.org/240 참고

쉘에서 secure.sh 실행

[code]
sh secure.sh
[/code]

apache2 설정

/etc/apache2/sites-available/moniwiki.dasomoli.org.conf

[code]
<VirtualHost *:80>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request’s Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
ServerName moniwiki.dasomoli.org

<Directory /var/www/moniwiki>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>

ServerAdmin dasomoli@gmail.com
DocumentRoot /var/www/moniwiki

# Available loglevels: trace8, …, trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn

ErrorLog ${APACHE_LOG_DIR}/moniwiki_error.log
CustomLog ${APACHE_LOG_DIR}/moniwiki.access.log combined

# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with “a2disconf”.
Include conf-available/serve-cgi-bin.conf
</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
[/code]

moniwiki 디렉토리에 index.html 생성

/var/www/moniwiki/index.html

[code]
<html>
<head>
<meta http-equiv=”refresh” content=”0; url=./wiki.php”>
</head>
<body onload=”javascript:window.location=’./wiki.php'”>
Please follow <a href=”wiki.php”>this link</a>
</body>
</html>
[/code]

[Raspberry Pi] 라즈베리파이에 미디어위키(MediaWiki) 설치

라즈베리파이의 OS, Raspbian에서는 패키지를 제공하므로 매우 간단하다.

sudo apt-get install mediawiki

 

설치하면 apache2의 available configuration에 mediawiki라는 새로운 configuration(/etc/apache2/conf-available/mediawiki.conf)이 생긴다.

아래의 Alias를 풀어서 /mediawiki 로 접근해도 된다.

#Alias /mediawiki /var/lib/mediawiki

 

난 VirtualHost를 이용한다.

/etc/apache2/sites-available/wiki.dasomoli.org.conf

<VirtualHost *:80>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        ServerName wiki.dasomoli.org

        ServerAdmin dasomoli@gmail.com
        DocumentRoot /var/lib/mediawiki

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/wiki_error.log
        CustomLog ${APACHE_LOG_DIR}/wiki.access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        Include conf-available/serve-cgi-bin.conf
</VirtualHost>

 

이제 mediawiki configuration을 enable 하자

sudo a2enconf mediawiki

wiki.dasomoli.org site도 enable하자

sudo a2ensite wiki.dasomoli.org.conf

apache2도 reload하자

sudo service apache2 reload

 

이제 wiki.dasomoli.org에 접속해서 mediawiki 설치를 시작한다.

설치가 끝나면 LocalSettings.php 파일을 저장할 수 있는데, 이 파일을 /etc/mediawiki/LocalSettings.php 로 저장한다.

다시 wiki.dasomoli.org로 접속해보면. 설치된 위키를 볼 수 있다!