混乱しがちだったのでまとめました。
なぜ使い分けたいのか?
ウェブアプリケーション開発においては、本番環境で不要なパッケージをインストールせずに済むからです。npm には dependencies に書かれたパッケージのみインストールする機能があるので、これを使ってインストール時間を短くできます。
また、本番環境に不要なものを置くのはセキュリティの観点から良くありません。
ライブラリ開発の場合は異なる
ライブラリ開発ではウェブアプリケーション開発と比べて、devDependencies の意味合いがやや異なります。devDependencies には、配布パッケージに含めるべきでないパッケージを書きます。ウェブアプリケーション開発ではビルド時間が縮むくらいの違いでした。しかし、ライブラリ開発では配布パッケージに含まれるか否かに関わるので、使い分けがとても重要です。
開発環境でしか使わないものは devDependencies
大抵、本番環境ではリポジトリをクローンしてきてビルドをするだけです。そのため、ESLint や Prettier は本番環境で使わないものは devDependencies に書きます。反対に、本番環境でも使いたいものは dependencies に書きます。
- dependencies に書くパッケージ
- ビルドに必要なパッケージ(webpack、TypeScript、Babelなど)
- 使用するライブラリ・フレームワーク(React や Vue)
- devDependencies に書くパッケージ
- Linter・Formatter(ESLint、Prettier 関連のパッケージ)
- テストフレームワーク(Jest など)
ただし、TypeScript には注意してください。TypeScript は build でも test でも使います。そのため、TypeScript関連のパッケージは一概に dependencies、devDependencies のどちらに含まれるか断定できません。一例をあげます。
- @types/jset: devDependencies(テストでしか使わないため)
- @types/react: dependencies(ビルド時に使うため)
- typescript: dependencies(ビルド時に使うため)
さらに: 開発環境でデプロイする場合
実は、わざわざ本番環境でクローン&ビルドせずとも、開発環境でビルドしたものをそのまま本番環境へデプロイできます*1。この場合、そもそも本番環境でパッケージのインストールをしないので、そこまで使い分けを意識する必要はありません。
ただし、CI/CDをしている場合は注意が必要です。この場合は結局、本番環境でクローン&ビルドしているのと変わりません。そのため、上で紹介したように dependencies と devDependencies を使い分ける必要があります。
ライブラリ開発について
ライブラリ開発の場合は多少異なりますが、考え方としてはほぼ同じです。
- devDependencies: 開発時に必要なもの(ビルドツール含む)
- dependencies: publish 後に必要なもの(require しているパッケージ)
ビルド関連ツールも devDependencies に含まれる点が異なっています。
まとめ
まず、ウェブアプリケーション開発とライブラリ開発に大別されます。
ウェブアプリケーション開発
- 開発環境でデプロイする場合:
- 特に必要なし
- CircleCI等でデプロイする場合、本番環境でクローン&ビルドする場合:
- dependencies
- ビルド時に使うもの
- devDependencies
- テスト時に使うもの、linter、formatter
ライブラリ開発
- dependencies
- 配布物に含めるべきもの(require するパッケージなど)
- devDependencies
- 開発時に使うもの(ビルド、テスト、linter、formatter)
*1:というより、本番環境でビルドせずに済むので、できることなら開発環境でデプロイできるようにするべきです