npmのパッケージを自分で開発している時に作成しているパッケージを使用したいことはありますか?
開発している途中で検証する際、npmなどのパッケージレジストリなどにpublishして使用したいprojectでnpm installで引っ張ってくる必要があり手間がかかってしまいます
npm linkを使用することでローカル内だけでnpmのパッケージ検証が可能になります

目次

環境

node -v
v18.8.0

npm -v
8.18.0

今回の完成形

private-hello-package

// private-hello-package/package.json
{
  "name": "private-hello-package",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "type": "module"
}
// index.js
const hello = () => {
  return 'hello world';
};

export {
  hello
};

my-project

// my-project/package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node index.js"
  },
  "author": "",
  "license": "ISC",
  "type": "module"
}
// index.js
import { hello } from "private-hello-package";

const result = hello();
console.log(result);

ディレクトリ構造

root
┗ package
  ┗ private-hello-package
    ┗ index.js
    ┗ package.json
┗ my-project
  ┗ index.js
  ┗ package.json
  ┗ package.lock.json

検証

パッケージ側

npm project作成

$ npm init

また、import文を使用するためpakcage.jsonにtype: moduleを追加する

// private-hello-package/package.json
{
  "name": "private-hello-package",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "type": "module"
}

文字列を出力するindex.jsを実装します

const hello = () => {
  return 'hello world';
};

export {
  hello
};

これでパッケージ側は完了です。パッケージを使用する側のprojectで使用したい関数はexportしてください

パッケージを使用するproject側

パッケージ側と同じくnpm初期化します

$ npm init

npm startコマンド、type: moduleを追加

// my-project/package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node index.js"
  },
  "author": "",
  "license": "ISC",
  "type": "module"
}

これで下準備は完了です

npm linkでシンボリックリンクを貼る

次にmy-projectでprivate-hello-packageを使用できるようにします 以下のコマンドでnpmシンボリックリンクが貼られます

$ cd {path}/package/private-hello-package

$ npm link

次に使用するprojectに移動してnpm linkでローカルでパッケージを使用できるようにします

$ cd {path}/my-project
$ npm link private-hello-package

これでnpm linkしたパッケージを使用できるようになったのでprivate-hello-packageを使用した実装をしてみます

// index.js
import { hello } from "private-hello-package";

const result = hello();
console.log(result);

実行してみましょう

$ npm start
hello world

出力されましたね

詳細

シンボリックリンクの確認

npm linkしたnode_moduleを見てみましょう

$ ls -l {path}/my-project/node_modules
xxxxxx  private-hello-package -> ../../private-hello-package

相対的にパッケージが指定されています

またnpm linkはglobalにシンボリックリンクが貼られています
筆者はnodenvでnodeを管理しているので下記のディレクトリで確認できます

ls  -l ~/.nodenv/versions/18.8.0/lib/node_module
xxxxxxxxxx private-hello-package -> ../../../../../blog/package/private-hello-package

private-hello-packageを指定するとローカルのprivate-hello-packageを指定していることがわかります

シンボリックリンクの解除

$ cd {path}/package/private-hello-package
# 使用する側のシンボリックリンクを解除します
$ npm unlink private-hello-package
# パッケージのシンボリックリンクをglobalから解除します
$ npm unlink -g private-hello-package

scopeでのnpm link

scopeを使用することによってpackageをグルーピングすることが可能です
scopeを使用したnpm linkの例は以下になります

// private-hello-package/package.json
{
  "name": "@scope/private-hello-package",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "type": "module"
}
$ cd {path}/package/private-hello-package
$ npm link

# @scopeのディレクトリ配下にある
$ ls  -l ~/.nodenv/versions/18.8.0/lib/node_modules/@scope
xxxxxxx private-hello-package -> ../../../../../../blog/package/private-hello-package

$ cd {path}/package/my-project
$ npm link @scope/private-hello-package

このような階層でシンボリックリンクが貼られています

my-project
┗ node_modules
  ┗ @scope
    ┗ private-hello-package

npm linkについて解説しました
npm linkを駆使して開発を爆速にしましょう!使用し終わったらシンボリックリンクの解除もお忘れなく

参考