僕が使っている npm のライブラリ image-ghost を 1.0.8 にアップデートしました。
そこでライブラリの編集が少し非効率に感じたため npm link を試しとみようと思いました。

npm ライブラリを開発するにあたり、まだ公開したくない段階でライブラリの動作チェックをしたいということが多々あると思います。
動作チェックの精度を向上させたい場合はどうしても npm publish を行う前に実際にインストールした node_modules と同じような動作環境の中でテストする必要があります。

npm link は公開前のパッケージのテストをしたいときなどに使うととても便利な機能です。

パッケージのディレクトリを指定して npm link を実行すると、実行したディレクトリ内でインストールしたパッケージをモジュールとして扱うことができるようになり、動作確認やコードの編集が容易になります。

npm link を実行するとグローバルの「{prefix}/lib/node_modules/(※1)」にシンボリックリンクが作られます。
またパッケージのディレクトリを指定して npm link を実行するとカレントディレクトリに node_modules ディレクトリが作成され、その中にも指定したパッケージのシンボリックリンクが作られます。

npm link はドキュメントが用意されています。
詳細についてはこちらから確認することができます。

※1
{prefix}は npm prefix [-g] を叩いた時に出力される値のことです。

パッケージの場所を指定する場合

コマンドの例

npm link はパッケージのディレクトリの場所を指定して実行することができます。
今回、コマンドの例を試すために「test-package-bin」をテスト用に作りました。
下記のディレクトリ構造で「test-package-bin」に入って「image-ghost」に向けて npm link ../image-ghost/ を実行します。

  1. ~/Documents/clone doitoyoaki$ ls -la
  2. total 0
  3. drwxr-xr-x 4 doitoyoaki staff 136 7 31 12:02 .
  4. drwxrwxrwx+ 13 doitoyoaki staff 442 7 26 15:20 ..
  5. drwxr-xr-x 15 doitoyoaki staff 510 7 28 15:28 image-ghost
  6. drwxr-xr-x 3 doitoyoaki staff 102 7 28 14:42 test-package-bin

下記の場合は「test-package-bin」を別階層にある「image-ghost」に対して npm link <pkg> を行なった例です。

  1. ~/Documents/clone/test-package-bin doitoyoaki$ npm link ../image-ghost/
  2. up to date in 0.28s
  3. /Users/doitoyoaki/.nodebrew/node/v8.2.1/bin/imageghost-task -> /Users/doitoyoaki/.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc/image-ghost/bin/image-ghost
  4. /Users/doitoyoaki/.nodebrew/node/v8.2.1/bin/imageghost-resize -> /Users/doitoyoaki/.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc/image-ghost/bin/resize
  5. /Users/doitoyoaki/.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc/image-ghost -> /Users/doitoyoaki/Documents/clone/image-ghost
  6. /Users/doitoyoaki/Documents/clone/test-package-bin/node_modules/@eq-inc/image-ghost -> /Users/doitoyoaki/.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc/image-ghost -> /Users/doitoyoaki/Documents/clone/image-ghost

シンボリックリンクが作成されていることを確認する

グローバルディレクトリ

実際にグローバルディレクトリにシンボリックリンクが作成されていることが確認できます。

  1. ~/.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc doitoyoaki$ ls -la
  2. total 8
  3. drwxr-xr-x 3 doitoyoaki staff 102 7 27 16:39 .
  4. drwxr-xr-x 4 doitoyoaki staff 136 7 26 11:40 ..
  5. lrwxr-xr-x 1 doitoyoaki staff 45 7 27 16:39 image-ghost -> /Users/doitoyoaki/Documents/clone/image-ghost
カレントディレクトリ

カレントディレクトリに対してシンボリックリンクが作成されていることが確認できます。

  1. ~/Documents/clone/test-package-bin/node_modules/@eq-inc doitoyoaki$ ls -la
  2. total 8
  3. drwxr-xr-x 3 doitoyoaki staff 102 7 27 16:57 .
  4. drwxr-xr-x 4 doitoyoaki staff 136 7 27 16:57 ..
  5. lrwxr-xr-x 1 doitoyoaki staff 73 7 27 16:57 image-ghost -> ../../../../../.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc/image-ghost

パッケージのディレクトリの場所を指定しない場合

package.json が置いてあるディレクトリでパッケージのディレクトリを指定せずに npm link を実行することができます。

  1. ~/Documents/clone/image-ghost doitoyoaki$ npm link
  2. npm notice created a lockfile as package-lock.json. You should commit this file.
  3. added 54 packages in 5.667s
  4. /Users/doitoyoaki/.nodebrew/node/v8.2.1/bin/imageghost-task -> /Users/doitoyoaki/.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc/image-ghost/bin/image-ghost
  5. /Users/doitoyoaki/.nodebrew/node/v8.2.1/bin/imageghost-resize -> /Users/doitoyoaki/.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc/image-ghost/bin/resize
  6. /Users/doitoyoaki/.nodebrew/node/v8.2.1/lib/node_modules/@eq-inc/image-ghost -> /Users/doitoyoaki/Documents/clone/image-ghost

npm install <folder> との違い

npm install <folder> を実行するとカレントディレクトリの node_modules にシンボリックリンクが置かれるので npm link <pkg> と同じことができます。
詳細についてはこちらから確認することができます。

コマンドの例

npm install <folder> を実行するとカレントディレクトリにパッケージがインストールされます。

  1. ~/Documents/clone doitoyoaki$ npm install image-ghost/
  2. npm WARN saveError ENOENT: no such file or directory, open '/Users/doitoyoaki/Documents/clone/package.json'
  3. npm notice created a lockfile as package-lock.json. You should commit this file.
  4. npm WARN enoent ENOENT: no such file or directory, open '/Users/doitoyoaki/Documents/clone/package.json'
  5. npm WARN clone No description
  6. npm WARN clone No repository field.
  7. npm WARN clone No README data
  8. npm WARN clone No license field.
  9.  
  10. + @eq-inc/image-ghost@1.0.8
  11. added 15 packages in 1.495s

シンボリックリンクが作成されていることが確認できます。

  1. ~/Documents/clone/node_modules/@eq-inc doitoyoaki$ ls -la
  2. total 8
  3. drwxr-xr-x 3 doitoyoaki staff 102 7 28 11:46 .
  4. drwxr-xr-x 18 doitoyoaki staff 612 7 28 11:46 ..
  5. lrwxr-xr-x 1 doitoyoaki staff 17 7 28 11:46 image-ghost -> ../../image-ghost

確認すると作成されるシンボリックリンクの向き先は npm link <pkg> の場合はグローバルディレクトリ、npm install <folder> の場合はカレントディレクトリを指していました。
このように npm install <folder> は npm link <pkg> と比べてシンボリックリンクの向き先がやや異なるようです。

npm 4 と npm 5 の違い

実は npm install <folder> -g は npm 4 と npm 5 とで挙動が違います。
下記二点の npm install <folder> -g を実行した後の結果を見比べてみるとその違いが確認できます。

npm 4.2.0

npm 4 ではグローバルの「{prefix}/lib/node_modules/」にパッケージそのものが置かれています。

  1. ~/.nodebrew/current/lib/node_modules/@eq-inc doitoyoaki$ ls -la
  2. total 0
  3. drwxr-xr-x 3 doitoyoaki staff 102 7 25 11:00 .
  4. drwxr-xr-x 4 doitoyoaki staff 136 7 25 11:00 ..
  5. drwxr-xr-x 16 doitoyoaki staff 544 7 25 11:00 image-ghost

npm 5.3.0

npm 5 ではグローバルの「{prefix}/lib/node_modules/」にシンボリックリンクが置かれています。

  1. ~/.nodebrew/current/lib/node_modules/@eq-inc doitoyoaki$ ls -la
  2. total 8
  3. drwxr-xr-x 3 doitoyoaki staff 102 7 25 11:08 .
  4. drwxr-xr-x 4 doitoyoaki staff 136 7 25 11:08 ..
  5. lrwxr-xr-x 1 doitoyoaki staff 45 7 25 11:08 image-ghost -> ../../../../../../Documents/clone/image-ghost

npm の github を確認してみると次の一文がありました。
npm install ./packages/subdir will now create a symlink instead of a regular installation.
npm の github の v5.0.0 項目から抜粋

本文を見る限りではバージョンは 5.0.0 以降から挙動が変わっているみたいです。

インストールされる場所

npm link <pkg> を実行するとグローバルディレクトリの「{prefix}/lib/node_modules/<package>」とカレントディレクトリの node_modules にパッケージがインストールされます。

npm install <folder> の場合

npm install <folder> の場合はカレントディレクトリの node_modules にのみインストールされます。
ただし npm install <folder> -g の場合はグローバルの「{prefix}/lib/node_modules/<package>」にのみインストールされます。

まとめ

パッケージのテストでは

ライブラリの編集には npm link を使用することで効率的に編集ができるようになるということが分かりました。

npm 4 以前のバージョンの問題点

npm 4 以前のバージョンだと npm install <folder> の場合は修正内容が反映されませんでした。
npm install <folder> はパッケージそのものがグローバルであれば「{prefix}/lib/node_modules/」、カレントディレクトリであれば node_modules にインストールされます。
そのため npm 4 では npm install <folder> と npm link <pkg> は用途によって使い分けなければなりません。

npm 5 以降では

npm 4 以前のバージョンではパッケージそのものがインストールされていたのですが、npm 5 以降のバージョンではパッケージからシンボリックリンクに変わっています。
従って、npm 5 以降のバージョンからは npm link <pkg> と npm install <folder> は実質、同じ挙動をするため、用途によって使い分ける必要性があまり感じられないということが分かりました。

感想

今回、npm link を試してみて、npm link の利便性や特長、注意点について触れることができました。
npm 4 では問題点がありましたが、npm 5 以降のバージョンをお使いであれば、 npm link <pkg> と npm install <folder> のどちらを使っても同じだと思いました。
僕個人としては npm install の方が馴染みがあるので npm install <folder> の方を使うかもしれません。

コメントの投稿