アプリケーションにおける、dependencies と devDependencies の扱いの違い
配布を目的としている npm ライブラリと、ライブラリを利用して機能を作るアプリケーションでは、dependencies の扱いが異なる。
この記事では主にアプリケーションではどうしたらいいのかに注目して、
- そもそも dependencies と devDependencies とはなんだったのか
- ライブラリとアプリケーションでこの2つに違いは生じるのか
- アプリケーションを作るときにはどのようにライブラリをインストールすればいいのか
を紹介する。
この記事が「アプリケーション開発で、ライブラリをインストールする際に dependencies かそうでないのか考える判断材料」となれば幸いだ。
著者の開発環境は以下の通り
- npm
- 8.11.0
- node
- 16.16.0
そもそも dependencies と devDependencies とはなんだったのか
以下で述べる違いしか存在しない。
例として
このライブラリを取り扱っていく。
dependencies
https://docs.npmjs.com/cli/v9/configuring-npm/package-json#dependencies
ライブラリをインストールする際のバージョン指定に用いられている。
まず npm で ramda をインストールしてみる。
npm i ramda@0.29.0
この結果、node_modules はこのようになる:
$ tree node_modules -L 1
node_modules
└── ramda
2 directories, 0 files
ramda しかインストールされていない。
これは、https://github.com/ramda/ramda/blob/v0.29.0/package.json#L92 を見てみると、dependencies: {} つまり、自分自身以外に依存関係がないためである。
次に、tsutils をインストールしてみる。
npm i tsutils@3.21.0
この結果、node_modules はこのようになる:
$ tree node_modules -L 1
node_modules
├── tslib
├── tsutils
└── typescript
4 directories, 0 files
tsutils 以外に「tslib」と「typescript」がインストールされた。
これは、https://github.com/ajafff/tsutils/blob/v3.21.0/package.json#L55 と https://github.com/ajafff/tsutils/blob/v3.21.0/package.json#L58 のとおり、peerDependencies と dependencies がインストールされたためである。
つまり、dependencies を指定しているライブラリを install すると、dependencies で指定されているライブラリも node_modules に入ってくる。
devDependencies
https://docs.npmjs.com/cli/v9/configuring-npm/package-json#devdependencies
開発するときにしか用いないライブラリをインストールする際のバージョン指定に用いられている。
今度は ramda ライブラリを開発しているリポジトリを git clone してみる。その上で npm install をする。
mkdir sample
cd sample
git clone https://github.com/ramda/ramda.git -b v0.29.0
cd ramda
npm install
これの結果、node_modules はこのようになる
$ tree node_modules -L 1
node_modules
├── @babel
├── @istanbuljs
├── @rollup
├── @sinonjs
├── @types
├── Base64
...
└── yeast
625 directories, 0 files
625 ディレクトリがインストールされた。
これは、https://github.com/ramda/ramda/blob/v0.29.0/package.json#L93 をみてみると、devDependencies で複数指定しているライブラリがインストールされたためである。devDependencies が依存しているライブラリもインストールされていくので、結果的に 625 にまで膨らんでいる。
ライブラリとアプリケーションでこの2つに違いは生じるのか
さきほどの章での違いでわかったように、ライブラリでdependenciesとdevDependenciesを指定すると、そのライブラリを install するときに node_modules に入ってくるものが変わることがわかった。
それでは、アプリケーションではどうだろうか。
配布を目的としないアプリケーションでは、dependenciesとdevDependenciesの区別はほぼない。
しかし、「dependencies のみをインストール」したいときには、アプリケーションでのこの区別は意味を持ってくる。
omit 引数
https://docs.npmjs.com/cli/v8/commands/npm-install#omit
npm には omit 引数が存在し、
npm i --omit=dev
とすると、devDependenciesをインストールさせないようにできる。
npm i -D eslint typescript
npm i react
rm -r ./node_modules
npm i --omit=dev
その結果はこれ:
$ tree node_modules -L 1
node_modules
├── @eslint
├── @eslint-community
├── @humanwhocodes
├── @nodelib
├── js-tokens
├── loose-envify
└── react
8 directories, 0 files
Scoped Packages はディレクトリのみできており、中身はない。dependencies で指定した react に関連するライブラリ だけがインストールされている。
ちなみに omit しない場合はこれ:
$ rm -r ./node_modules
$ npm i
$ tree node_modules -L 1
node_modules
├── @eslint
├── @eslint-community
├── @humanwhocodes
├── @nodelib
├── acorn
├── acorn-jsx
├── ajv
├── ansi-regex
...
└── yocto-queue
96 directories, 0 files
アプリケーションを作るときにはどのようにライブラリをインストールすればいいのか
以上をまとめると、この様になる。
- omit 引数を使う場合は開発でしか使わないときは
devDependenciesに指定、そうでないときはdependenciesに指定する - omit 引数を使わない場合は区別しないでいい
当然だが、omit の件以外でも、dependencies と devDependencies フィールドを見て何かしらの処理をするようなサービスを使っていたらこの限りではない。
この記事を書いたあとに教えてもらったのだが、どうやら、npm install には dependencies のみインストールする
--productionというものがあるので、そっちを使ったほうがいいと思う。