🟩

見知らぬ npm dependencies の書き方に出会った

に公開

package.json は、NodeJS プロジェクトの設定ファイルで、ライブラリ依存関係や設定情報を管理するファイルのこと。
ライブラリの依存関係は、 dependencies に記載されるが見知らぬ書き方に出会ったので、調査結果のまとめ。

出会ったパターン

package.json
"dependencies": {
  "example_lib": "github:slopwell/example_lib#feature"
}

URL Dependency とは

これは "github:username/repo#branch" の書式で、URL Dependency と呼ばれるもの。
GitHub 上の特定リポジトリの特定ブランチを参照してライブラリを取得する方法らしい

正確な記法は下記の通り

<protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]

https://docs.npmjs.com/cli/v9/configuring-npm/package-json#urls-as-dependencies

動作検証「もしブランチが削除されたら?」

簡単に下記の観点で動作検証してみる

  • A: GitHub 上の特定リポジトリの特定ブランチを参照してライブラリを取得できるか(正常系)
  • B: GitHub のクレデンシャル無しのアクセスで public リポジトリにアクセスできるか(準正常系)
  • C: 削除されたブランチを指定した場合にどうなるか(異常系)

動作検証の結果「ブランチが消えたらinstallが失敗する(当然)」

検証項目 結果
A 正常系 取得できた
B 認証情報無し エラーで取得できず
C ブランチ削除 エラーで取得できず

「B 認証情報無し」、「C ブランチ削除」は、test ブランチを作成 → 削除し、 npm install 実行時に下記のようなエラーメッセージが表示された

  • このとき、 nodoe_modulespackage-lock.json は生成されなかった

B GitHub向けの信頼情報無しのエラーメッセージ

log
$ npm install
npm error code 128
npm error An unknown git error occurred
npm error command git --no-replace-objects ls-remote ssh://git@github.com/user/repository.git
npm error Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
npm error git@github.com: Permission denied (publickey).
npm error fatal: Could not read from remote repository.
npm error
npm error Please make sure you have the correct access rights
npm error and the repository exists.
npm error A complete log of this run can be found in: /home/***/.npm/_logs/2025-11-17T10_15_01_304Z-debug-0.log

C ブランチ削除のエラーメッセージ

log
$ npm install
npm ERR! code 1
npm ERR! The git reference could not be found
npm ERR! command git --no-replace-objects checkout test
npm ERR! error: pathspec 'test' did not match any file(s) known to git

npm ERR! A complete log of this run can be found in: ~/.npm/_logs/2025-11-16T01_36_41_915Z-debug-0.log
ログファイルは下記の通り
~/.npm/_logs/2025-11-16T01_36_41_915Z-debug-0.log
0 verbose cli /home/***/.volta/tools/image/node/20.19.4/bin/node /home/***/.volta/tools/image/npm/10.2.3/bin/npm-cli.js
1 info using npm@10.2.3
2 info using node@v20.19.4
3 timing npm:load:whichnode Completed in 2ms
4 timing config:load:defaults Completed in 2ms
5 timing config:load:file:/home/***/.volta/tools/image/npm/10.2.3/npmrc Completed in 4ms
6 timing config:load:builtin Completed in 4ms
7 timing config:load:cli Completed in 2ms
8 timing config:load:env Completed in 0ms
9 timing config:load:file:/home/***/***/***sandbox/hoge/.npmrc Completed in 0ms
10 timing config:load:project Completed in 3ms
11 timing config:load:file:/home/***/.npmrc Completed in 0ms
12 timing config:load:user Completed in 1ms
13 timing config:load:file:/home/***/.volta/tools/image/node/20.19.4/etc/npmrc Completed in 0ms
14 timing config:load:global Completed in 0ms
15 timing config:load:setEnvs Completed in 1ms
16 timing config:load Completed in 13ms
17 timing npm:load:configload Completed in 13ms
18 timing config:load:flatten Completed in 3ms
19 timing npm:load:mkdirpcache Completed in 1ms
20 timing npm:load:mkdirplogs Completed in 0ms
21 verbose title npm install
22 verbose argv "install"
23 timing npm:load:setTitle Completed in 1ms
24 timing npm:load:display Completed in 1ms
25 verbose logfile logs-max:10 dir:/home/***/.npm/_logs/2025-11-16T01_36_41_915Z-
26 verbose logfile /home/***/.npm/_logs/2025-11-16T01_36_41_915Z-debug-0.log
27 timing npm:load:logFile Completed in 9ms
28 timing npm:load:timers Completed in 0ms
29 timing npm:load:configScope Completed in 0ms
30 timing npm:load Completed in 41ms
31 timing arborist:ctor Completed in 1ms
32 silly logfile start cleaning logs, removing 1 files
33 silly logfile done cleaning log files
34 timing arborist:ctor Completed in 0ms
35 timing idealTree:init Completed in 16ms
36 timing idealTree:userRequests Completed in 0ms
37 silly idealTree buildDeps
38 silly fetch manifest url-test@github:slopwell/urls-as-dependencies#test
39 silly placeDep ROOT url-test@ OK for: hoge@1.0.0 want: github:slopwell/urls-as-dependencies#test
40 timing idealTree:#root Completed in 1186ms
41 timing idealTree:node_modules/url-test Completed in 0ms
42 timing idealTree:buildDeps Completed in 1188ms
43 timing idealTree:fixDepFlags Completed in 0ms
44 timing idealTree Completed in 1206ms
45 timing command:install Completed in 1218ms
46 verbose stack Error: The git reference could not be found
46 verbose stack     at makeError (/home/***/.volta/tools/image/npm/10.2.3/node_modules/@npmcli/git/lib/make-error.js:26:13)
46 verbose stack     at /home/***/.volta/tools/image/npm/10.2.3/node_modules/@npmcli/git/lib/spawn.js:37:26
46 verbose stack     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
46 verbose stack     at async /home/***/.volta/tools/image/npm/10.2.3/node_modules/pacote/lib/git.js:268:19
46 verbose stack     at async withTempDir (/home/***/.volta/tools/image/npm/10.2.3/node_modules/@npmcli/fs/lib/with-temp-dir.js:21:14)
46 verbose stack     at async #nodeFromEdge (/home/***/.volta/tools/image/npm/10.2.3/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js:1049:19)
46 verbose stack     at async #buildDepStep (/home/***/.volta/tools/image/npm/10.2.3/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js:917:11)
46 verbose stack     at async Arborist.buildIdealTree (/home/***/.volta/tools/image/npm/10.2.3/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js:196:7)
46 verbose stack     at async Promise.all (index 1)
46 verbose stack     at async Arborist.reify (/home/***/.volta/tools/image/npm/10.2.3/node_modules/@npmcli/arborist/lib/arborist/reify.js:159:5)
47 verbose cwd /home/***/sandbox/hoge
48 verbose Linux 6.6.87.1-microsoft-standard-WSL2
49 verbose node v20.19.4
50 verbose npm  v10.2.3
51 error code 1
52 error The git reference could not be found
53 error command git --no-replace-objects checkout test
54 error error: pathspec 'test' did not match any file(s) known to git
55 verbose exit 1
56 timing npm Completed in 1430ms
57 verbose unfinished npm timer reify 1763257002125
58 verbose unfinished npm timer reify:loadTrees 1763257002131
59 verbose code 1
60 error A complete log of this run can be found in: /home/***/.npm/_logs/2025-11-16T01_36_41_915Z-debug-0.log

検証資材

インストールされるダミーモジュールの作成

空のリポジトリ urls-as-dependencies を作成し、下記ファイルを直下に配置

index.js
function sayHello() {
  console.log("hello. world");
}

module.exports = sayHello;
package.json
{
  "name": "dummy-npm-lib",
  "version": "1.0.0",
  "description": "dummy library",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
ダミーモジュールをインストールするプロジェクトの作成

npm init → 下記を json に追記 → npm install を実行

package.json
  "dependencies": {
    "url-test": "github:slopwell/urls-as-dependencies#main"
  },

dependencies and devDependencies のおさらい

Dependency はセマンティックバージョンで記載される
dependencies

  • プロダクションビルドで必要なライブラリ
  • npm install <Lib> or npm instanll <Lib> --save-prod (-S)

devDependencies

  • ローカルや開発ビルドで必要なライブラリ
  • npm instanll <Lib> --save-dev (-D)
package.json
"name": "my_package",
"version": "1.0.0",
"dependencies": {
  "my_dep": "^1.0.0",
  "another_dep": "~2.2.0"
},
"devDependencies" : {
  "my_test_framework": "^3.1.0",
  "another_dev_dep": "1.0.0 - 1.2.0"
}

https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file

セマンティックバージョンの記載方法

~ , ^ に関する説明
セマンティックバージョンは、 9.7.12 のようなピリオド区切りの三桁で表現されるバージョン記法
それぞれ、Major, Minor, Patch に対応する
package.json では、以下のように記載することで、特定のバージョン範囲を指定できる

package.json での記法 説明 npm install 時の挙動
9.7.12 Patch まで完全一致 9.7.12 only
9.7.x or ~9.7.12 Patch の最新 9.7 系の LATEST かつ 9.8.0 未満
9.x or ^9.7.12 Minor の最新 9 系の LATEST かつ 10.0.0 未満
x or * Major の最新 LATEST
9.7.10 - 9.8.12 範囲指定 9.7.10 以上 9.8.12 以下
>9.7.12 指定バージョンより新しい 9.7.12 より新しいバージョン (ほかの比較演算子も同様)

https://docs.npmjs.com/about-semantic-versioning

https://semver.org


URL Dependencyを使うときは、commit-ish を使う or npmに公開されるのを待つのがよさげ

  • ブランチ名を指定すると可読性が上がるが、マージ時に消える可能性がある
  • commit-ishを指定すると保守性は上がるが、何を指定しているのか都度確認が必要

Discussion