Node.js開発者が知るべき npm install
の基本と詳細
Node.js開発において、npm install
コマンドは日々のワークフローの根幹をなすものです。しかし、単にパッケージをインストールするだけでなく、その裏側で行われていることや、利用できる様々なオプション、そして起こりうる問題を理解しているかどうかで、開発効率やプロジェクトの安定性は大きく変わります。
この記事では、Node.js開発者が知っておくべき npm install
の基本から、パッケージのバージョン管理、依存関係の種類、package.json
と package-lock.json
の役割、よく使うオプション、そしてトラブルシューティングまで、網羅的かつ詳細に解説します。約5000語のボリュームで、あなたの npm install
に関する理解を深め、より堅牢な開発を進めるための一助となることを目指します。
はじめに:なぜ npm install
を深く理解する必要があるのか
Node.jsのエコシステムは、npm (Node Package Manager) と呼ばれる巨大なパッケージマネージャーによって支えられています。npmは、世界中の開発者が作成した膨大な数のモジュールやライブラリ(これらをまとめて「パッケージ」と呼びます)を共有・再利用するための仕組みを提供します。これにより、開発者はゼロから全てを作る必要がなくなり、既存の高品質なコードを活用して効率的にアプリケーションを開発できます。
npm install
は、その名の通り、これらのパッケージをあなたのプロジェクトに取り込むためのコマンドです。しかし、このコマンドの実行は、単にファイルがダウンロードされるだけでなく、プロジェクトの依存関係の管理、バージョン解決、スクリプトの実行など、様々な複雑な処理を含んでいます。
- 依存関係の明確化: プロジェクトが必要とする外部ライブラリを正確に定義し、チームメンバー間やデプロイ環境間で同じ依存関係を再現することを保証します。
- 環境間の差異の吸収: 異なるOSや環境でも、必要なパッケージとその依存関係を正しくインストールできるようにします。
- 開発効率の向上: 必要なツールやライブラリを素早くプロジェクトに追加し、開発をスムーズに進められます。
- プロジェクトの安定性: 依存関係のバージョンを適切に管理することで、予期せぬライブラリの更新による問題を防ぎます。
これらの理由から、npm install
を「動けばOK」ではなく、その仕組みや挙動をしっかりと理解することが、Node.js開発者にとって不可欠なのです。
npmとパッケージ管理の基本
npm install
の話に入る前に、npmとパッケージ管理の基本的な概念を整理しておきましょう。
- パッケージ (Package): 特定の機能を持つJavaScriptコードの集まりで、通常は一つ以上のファイルやディレクトリで構成されます。各パッケージは
package.json
というファイルでその情報(名前、バージョン、説明、依存関係など)を定義します。 - npm レジストリ (npm Registry): 世界中の公開されているnpmパッケージが登録・管理されている中央データベースです。
npm install
コマンドは、デフォルトではこの公式レジストリからパッケージをダウンロードします。企業内などで独自のプライベートレジストリを運用することも可能です。 - 依存関係 (Dependencies): あるパッケージ(あなたのプロジェクトも含む)が、その機能を実現するために必要とする他のパッケージのことです。例えば、WebフレームワークのExpressは、ルーティングやミドルウェアなどの機能を提供するために、内部で他のいくつかのパッケージに依存しています。
node_modules
ディレクトリ:npm install
コマンドを実行すると、インストールされたパッケージとその依存関係は、通常、プロジェクトのルートディレクトリにあるnode_modules
という特別なディレクトリ内に配置されます。Node.jsは、このnode_modules
ディレクトリ内を検索してモジュールを読み込みます。
npmは、これらの要素を組み合わせて、依存関係の解決、バージョンの競合回避、パッケージのダウンロードと配置を行います。
npm install
の最も基本的な使い方:ローカルインストール
npm install
の最も一般的で基本的な使い方は、特定のパッケージをプロジェクトローカルにインストールすることです。これは、あなたの特定のプロジェクトだけがそのパッケージを利用できるようにするもので、推奨される方法です。
コマンドの書式
bash
npm install <package-name>
または
bash
npm i <package-name>
i
は install
の短縮形です。
例: プロジェクトにHTTPリクエストを行うための axios
パッケージをインストールしたい場合
bash
npm install axios
このコマンドを実行すると、以下のことが起こります。
- npmは
axios
パッケージの最新安定版の情報をnpmレジストリから取得します。 axios
パッケージ自身が依存している他のパッケージ(「推移的依存関係」と呼びます)を特定します。- 指定されたパッケージ (
axios
) とその全ての依存パッケージをnpmレジストリからダウンロードします。 - ダウンロードしたパッケージを、プロジェクトのルートディレクトリ直下に
node_modules
というディレクトリを作成し、その中に配置します。npm v3以降では、依存関係がフラットな構造で配置されるようになり、ディレクトリの深さが浅くなりました。 - プロジェクトのルートディレクトリにある
package.json
ファイルを開き、dependencies
というセクションにaxios
とそのバージョン情報を自動的に追加します。 package-lock.json
ファイルが存在しない場合は新しく作成し、存在する場合は更新します。このファイルには、インストールされた全てのパッケージとその依存関係の正確なツリー構造、ダウンロード元、整合性情報などが記録されます。
package.json
への記録(dependencies
と devDependencies
)
package.json
ファイルは、Node.jsプロジェクトの設定、依存関係、スクリプトなどを定義するマニフェストファイルです。npm install <package-name>
コマンドを実行すると、デフォルトではインストールしたパッケージは package.json
の dependencies
というフィールドに記録されます。
json
// package.json の一部
{
"name": "my-nodejs-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.21.1" // <-- ここに記録される
},
"devDependencies": {
// 開発時のみ必要なパッケージ
}
}
dependencies
に記録されるパッケージは、アプリケーションが実行される本番環境でも必要となるライブラリです。例えば、Webサーバーフレームワーク (Express)、データベースドライバ (mongoose)、HTTPクライアント (axios) などがこれにあたります。
一方、開発時のみ必要で、アプリケーションの実行時には不要なパッケージは、devDependencies
という別のフィールドに記録するのが慣習です。これには、テストフレームワーク (Jest, Mocha)、ビルドツール (Webpack, Parcel)、トランスパイラ (Babel)、Linter (ESLint)、Formatter (Prettier) などが含まれます。
devDependencies
にインストールしたい場合は、--save-dev
オプションを付けてインストールします。
bash
npm install jest --save-dev
または短縮形の -D
を使います。
bash
npm install jest -D
npm v5.0.0 以降では、npm install <package-name>
はデフォルトで --save
オプションが有効になっており、dependencies
に記録されます。それ以前のバージョンでは明示的に --save
を付ける必要がありましたが、現在は不要です。同様に、npm install <package-name> --save-dev
または -D
も、オプションを省略するとデフォルトで dependencies
に入るため、devDependencies
に入れたい場合は -D
(または --save-dev
) を明示的に指定する必要があります。
package-lock.json
との連携
npm install
は、パッケージをインストールするだけでなく、package-lock.json
ファイルを生成または更新します。このファイルの役割については後述しますが、非常に重要です。
package-lock.json
は、node_modules
ディレクトリの正確な構造と、そこにインストールされた各パッケージのバージョン、ダウンロード元(npmレジストリからのURL)、整合性チェックのためのハッシュ値などを詳細に記録します。これにより、次に誰かが同じ package.json
と package-lock.json
を使って npm install
を実行したときに、全く同じバージョンのパッケージ群が、全く同じ構造でインストールされることが保証されます。
これは、チーム開発において「私の環境では動くのに、君の環境では動かない」といった問題を解決する上で非常に重要です。package-lock.json
は、プロジェクトの依存関係を確定的に(deterministically)固定するためのファイルであり、通常は package.json
と一緒にバージョン管理システム(Gitなど)にコミットすべきファイルです。
パッケージのバージョン管理
依存関係のバージョンをどのように指定し、管理するかは、プロジェクトの安定性に大きく影響します。npmはSemVer (Semantic Versioning) というバージョン管理の慣習に基づいてパッケージのバージョンを扱います。
セマンティックバージョニング (SemVer) の基本
ほとんどのnpmパッケージは、X.Y.Z
の形式でバージョン番号が付けられています。
- X (メジャーバージョン – Major): 後方互換性のない変更が行われた場合に増加します。
- Y (マイナーバージョン – Minor): 後方互換性のある機能追加が行われた場合に増加します。
- Z (パッチバージョン – Patch): 後方互換性のあるバグ修正が行われた場合に増加します。
SemVerの思想は、「同じメジャーバージョン内での更新(マイナーバージョンやパッチバージョンの増加)は、既存のコードを壊さないはずだ」というものです。
package.json
におけるバージョン指定方法
package.json
の dependencies
や devDependencies
では、インストールしたいパッケージのバージョンを指定できます。最も一般的なのは、バージョン番号の前に記号(チルダ ~
やキャレット ^
)を付ける方法です。
-
^
(キャレット): 指定したバージョン(X.Y.Z
)の、メジャーバージョン X を変更しない範囲での最新版を許可します。つまり、^1.2.3
と指定した場合、1.2.3
から1.x.x
の範囲(例えば1.2.4
,1.3.0
,1.99.0
など)の最新版がインストールされます。ただし、2.0.0
以降はインストールされません。これはnpmのデフォルトのバージョン指定方法です。SemVerに従っていれば、同じメジャーバージョン内のアップデートは互換性があるはずだ、という考えに基づいています。- 例:
^1.2.3
->1.2.3 <= version < 2.0.0
^0.2.3
->0.2.3 <= version < 0.3.0
(0.x.x系では、マイナーバージョンの変更が実質的なメジャーバージョンの変更とみなされることがあります)^0.0.3
->0.0.3 <= version < 0.0.4
- 例:
-
~
(チルダ): 指定したバージョン(X.Y.Z
)の、マイナーバージョン Y を変更しない範囲での最新のパッチバージョンを許可します。つまり、~1.2.3
と指定した場合、1.2.3
から1.2.x
の範囲(例えば1.2.4
,1.2.5
など)の最新版がインストールされますが、1.3.0
や2.0.0
はインストールされません。- 例:
~1.2.3
->1.2.3 <= version < 1.3.0
- 例:
-
厳密なバージョン: 特定のバージョンのみをインストールしたい場合は、記号を付けずにバージョン番号だけを指定します。
- 例:
"lodash": "4.17.21"
->4.17.21
以外のバージョンは絶対にインストールされません。これは--save-exact
オプションを使ってインストールした場合に利用されます。
- 例:
-
ワイルドカード (
*
) またはバージョン指定なし: 利用可能な最新バージョンをインストールします。これは通常、推奨されません。依存関係が不安定になる可能性があります。- 例:
"lodash": "*"
または"lodash": ""
- 例:
-
範囲指定: 比較演算子を使ってバージョン範囲を指定できます。
> 1.2.0
: 1.2.0より新しいバージョン>= 1.2.0
: 1.2.0以上のバージョン< 2.0.0
: 2.0.0より古いバージョン<= 2.0.0
: 2.0.0以下のバージョン1.0.0 - 2.0.0
: 1.0.0から2.0.0までのバージョン(両端を含む)> 1.0.0 < 2.0.0
: 1.0.0より新しく、2.0.0より古いバージョン||
: 複数の範囲を組み合わせます。例:^1.0.0 || ^2.0.0
(1.x.x または 2.x.x の最新版)
npm install
時のバージョン解決
npm install
(引数なし) を実行すると、npmは package.json
に記述されたバージョン指定(例: ^1.2.3
)と、package-lock.json
に記録された具体的なバージョン情報を参照して、インストールすべきパッケージのバージョンを決定します。
package-lock.json
が存在する場合:- npmは基本的に
package-lock.json
に記録されている通りのバージョンと依存関係ツリーを再現しようとします。これにより、前回のインストールと同じ結果が保証されます。 - ただし、もし
package.json
のバージョン指定がpackage-lock.json
のバージョンと互換性がない場合や、新しいパッケージがpackage.json
に追加されている場合は、package.json
に従って解決を行い、package-lock.json
を更新します。
- npmは基本的に
package-lock.json
が存在しない場合:- npmは
package.json
に記述されたバージョン指定に従って、npmレジストリから条件を満たす最新のバージョンをダウンロードします。 - 依存関係ツリーを解決し、
node_modules
ディレクトリに配置します。 - 新しく
package-lock.json
ファイルを作成し、今回インストールされた依存関係の正確な情報を記録します。
- npmは
この仕組みにより、package-lock.json
は「このプロジェクトはこのバージョンの依存関係で動作確認されています」という状態を記録するスナップショットとして機能します。だからこそ、package.json
と一緒にバージョン管理下に置くことが推奨されるのです。
特定のバージョンのインストール
開発中に、特定のバージョンのパッケージをインストールしたい場合があります。これは、バグのある最新版を避けたり、古いライブラリとの互換性を保ったりする場合に便利です。
bash
npm install <package-name>@<version>
例: axios
のバージョン 0.20.0
をインストールしたい場合
bash
npm install [email protected]
このコマンドは、指定されたバージョンのパッケージをインストールし、package.json
の該当エントリをそのバージョン(通常は厳密な指定 0.20.0
になります)に更新し、package-lock.json
も更新します。
ローカルインストールとグローバルインストール
npm install
には、プロジェクトローカルへのインストールと、システム全体へのグローバルインストールという2つの主要なモードがあります。
グローバルインストール (-g
オプション)
bash
npm install <package-name> -g
または
bash
npm i <package-name> -g
このコマンドは、指定されたパッケージを node_modules
ディレクトリではなく、システムのグローバルな場所にインストールします。グローバルにインストールされたパッケージは、どのディレクトリからでもコマンドラインツールとして実行できるようになります。
グローバルインストールの主な用途:
- CLIツール: Node.jsベースのコマンドラインインターフェースを持つツール(例:
create-react-app
,Vue CLI (@vue/cli)
,nodemon
,webpack
,eslint
など)。これらのツールは、特定のプロジェクト内で使うというよりは、システム全体で利用することが多いため、グローバルインストールが適しています。- 例:
npm install -g create-react-app
- 例:
- パッケージマネージャー:
yarn
やpnpm
といった代替パッケージマネージャー自体も、npmを使ってグローバルにインストールすることが多いです。- 例:
npm install -g yarn
- 例:
注意点:
- グローバルインストールされたパッケージは、プロジェクトの
package.json
には記録されません。そのため、プロジェクトの依存関係として明確に管理されません。 - 異なるプロジェクトが同じグローバルパッケージの異なるバージョンに依存している場合、バージョン競合の問題が発生する可能性があります。これが、多くの開発者がCLIツール以外はグローバルインストールを避ける理由の一つです。
- グローバルインストール先のパスは、OSやnpmの設定によって異なります。
npm root -g
コマンドで確認できます。
グローバルインストールされたコマンドの実行パス:
グローバルにインストールされた実行可能ファイル(コマンド)は、システムのPATH環境変数によって認識される場所に配置されます。npm bin -g
コマンドを実行すると、グローバルインストールされたコマンドが配置されるディレクトリのパスが表示されます。
bash
npm bin -g
このパスがシステムのPATHに含まれていないと、グローバルインストールしたコマンドをターミナルから直接実行できない場合があります。その場合は、システムの環境変数設定を更新する必要があります。
ローカルインストールが推奨される理由
CLIツールなどシステム全体で使う明確な目的がある場合を除き、ほとんどのパッケージはプロジェクトローカルにインストールするべきです。
- 依存関係の明確化: プロジェクトが必要とする全てのライブラリが
package.json
に記録され、誰でも簡単に確認できます。 - 環境の再現性:
package.json
とpackage-lock.json
を使えば、チームメンバーやデプロイ環境で全く同じ依存関係ツリーを再現できます。グローバル依存は、環境ごとにインストールが必要になり、バージョンも管理外になりがちです。 - バージョンの分離: 各プロジェクトは独自の
node_modules
ディレクトリを持つため、異なるプロジェクト間で同じパッケージの異なるバージョンを依存していても衝突しません。
例えば、特定のプロジェクトでWebpackの特定のバージョンが必要な場合、それをローカルにインストールすれば、他のプロジェクトが別のバージョンのWebpackを使っていても影響ありません。もしWebpackをグローバルにインストールしていたら、どちらかのプロジェクトで問題が発生する可能性があります。多くの最新のCLIツールは、プロジェクトローカルにインストールされたバージョンを優先的に使用するようになっていますが、基本的にはローカルインストールがより安全で管理しやすい方法です。
最近では、プロジェクトローカルにインストールしたCLIツールを package.json
の scripts
フィールドから実行するのが一般的です。例えば、ローカルにインストールしたWebpackを実行する場合:
json
// package.json の一部
{
// ...
"scripts": {
"build": "webpack --config webpack.config.js"
},
"devDependencies": {
"webpack": "^5.0.0",
"webpack-cli": "^4.0.0"
}
// ...
}
このように設定しておけば、npm run build
コマンドでプロジェクトローカルの webpack
コマンドが実行されます。これにより、グローバルインストールせずにプロジェクト固有のツールバージョンを使用できます。
依存関係の管理
プロジェクトの依存関係は時間の経過とともに変化します。新しいパッケージを追加したり、既存のパッケージを更新したり、不要になったパッケージを削除したりする必要があります。
package.json
からすべての依存関係をインストール (npm install
引数なし)
クローンしたリポジトリで開発を始めるときや、プロジェクトの依存関係を最新の状態に同期したいときなど、package.json
ファイルにリストされている全ての依存関係をまとめてインストールしたい場合があります。
この場合、引数を付けずに npm install
コマンドを実行します。
bash
npm install
このコマンドを実行すると、npmは現在のディレクトリの package.json
ファイルを読み込み、その中の dependencies
、devDependencies
、optionalDependencies
、peerDependencies
(npm v7以降の挙動に注意) フィールドにリストされている全てのパッケージを、package-lock.json
の情報を参照しながら node_modules
ディレクトリにインストールします。
これは、プロジェクトをセットアップする際の最初のステップとして非常に重要です。
開発環境と本番環境の違い (--production
オプション)
アプリケーションを開発する際にはテストツールやビルドツールなど様々なパッケージが必要ですが、アプリケーションを本番環境にデプロイして実行する際には、これらの開発用のパッケージは不要なことが多いです。本番環境では、アプリケーションの実行に最低限必要なパッケージだけをインストールすることで、デプロイパッケージのサイズを小さくし、インストール時間を短縮できます。
npm install
コマンドに --production
オプションを付けると、devDependencies
にリストされているパッケージを除外して、dependencies
と optionalDependencies
のパッケージだけをインストールします。
bash
npm install --production
これは、アプリケーションをコンテナイメージにビルドする際や、サーバーにデプロイする際のスクリプトなどで非常によく使われます。
また、環境変数 NODE_ENV
が production
に設定されている場合(多くのPaaSやホスティングサービスでデフォルト設定)、引数なしの npm install
コマンドは自動的に --production
オプションが有効になったかのように振る舞います。つまり、本番環境で NODE_ENV=production
と設定されている状態で npm install
を実行すれば、devDependencies
はインストールされません。
既存プロジェクトへの参加時
チーム開発でGitリポジトリなどをクローンして既存のプロジェクトに参加する際の手順は以下のようになります。
- リポジトリをクローンします。
bash
git clone <repository-url>
cd <project-directory> - プロジェクトの依存関係をインストールします。
bash
npm install
このコマンドがpackage.json
とpackage-lock.json
を参照し、必要なパッケージ全てをnode_modules
にインストールしてくれます。
これにより、他の開発者と同じ依存関係の状態で開発を始められます。
package-lock.json
の詳細
package-lock.json
はnpm v5から導入された非常に重要なファイルです。その役割と内容はより深く理解する価値があります。
なぜ package-lock.json
が必要か?
package.json
に記述されたバージョン指定(例: ^1.2.3
)は、ある程度のバージョン範囲を許容します。これは、依存パッケージのバグ修正や小規模な機能追加を自動的に取り込むことができるという利点がある一方で、「昨日動いていたコードが、npm install
を実行したら今日は動かなくなった」という問題を潜在的に引き起こします。これは、許可された範囲内でパッケージの新しいバージョンがリリースされ、それがインストールされた結果、後方互換性のない変更や新しいバグが含まれていた場合に起こり得ます。
このような「特定の package.json
に対応する node_modules
ディレクトリの状態」を確定的に(再現可能に)記録するために package-lock.json
が存在します。このファイルは、依存関係ツリー内の各パッケージについて、以下の情報を詳細に記録します。
- インストールされた正確なバージョン (
version
フィールド) - パッケージのダウンロード元URL (
resolved
フィールド) - ダウンロードされたパッケージの整合性を確認するためのハッシュ値 (
integrity
フィールド)。これにより、ダウンロードしたファイルが改ざんされていないことを保証します。 - そのパッケージ自身が依存しているパッケージ (
requires
フィールド)。ただし、これはそのパッケージのpackage.json
の依存関係を示すものであり、実際にフラット化されたnode_modules
内のどこに依存パッケージが配置されているかを示すものではありません。 - 実際に
node_modules
ディレクトリのどこに配置されているかの構造 (dependencies
オブジェクト内のネスト構造)。
npm install
と package-lock.json
の関係(再確認)
npm install
コマンドの挙動は、package-lock.json
ファイルの存在によって変わります。
package-lock.json
が存在する場合:- npmは基本的に
package-lock.json
を「信頼できる情報源」として扱います。 package-lock.json
に記述されている通りのパッケージのバージョンと依存関係ツリーを再現しようとします。node_modules
ディレクトリの内容をpackage-lock.json
の状態と一致させます。- ただし、もし
package.json
の依存関係が変更されている(新しいパッケージが追加された、バージョン指定が変わったなど)場合、npmはpackage.json
を優先して新しい依存関係を解決し、それに応じてpackage-lock.json
を更新します。
- npmは基本的に
package-lock.json
が存在しない場合:- npmは
package.json
に記述されたバージョン指定に従って依存関係を解決し、最新の許可されたバージョンをインストールします。 - インストールが完了した後、現在の
node_modules
ディレクトリの状態を反映したpackage-lock.json
を新しく生成します。
- npmは
この挙動から分かるように、package-lock.json
は、一度動作確認が取れた依存関係の状態を「ロック」し、その状態を再現するためのファイルです。
Git管理の必要性
前述の通り、package-lock.json
はプロジェクトの依存関係の状態を確定的に再現するために不可欠なファイルです。そのため、package.json
と同様に、バージョン管理システム(Gitなど)にコミットして、チームメンバー間で共有するべきです。
.gitignore
ファイルに package-lock.json
を追加してしまうと、他のチームメンバーがプロジェクトをクローンした際に package.json
に基づいて依存関係がインストールされます。しかし、このときインストールされるパッケージの正確なバージョンは、そのメンバーが npm install
を実行した時点での最新版に依存するため、あなたや他のメンバーの環境とは異なる可能性があり、同じバグを踏むことになります。
package-lock.json
を共有することで、どの開発者も、あるいはCI/CD環境も、全く同じ依存関係のセットをインストールすることが保証され、開発環境と本番環境の差異による問題を大幅に減らすことができます。
.gitignore
に node_modules
ディレクトリを追加することは一般的かつ推奨されますが、package-lock.json
は絶対に含めるべきではありません。
一般的な npm install
のオプションとフラグ
npm install
コマンドには様々なオプションがあり、インストール挙動を細かく制御できます。ここでは、よく使う重要なオプションを紹介します。
-
-S
,--save
:npm install <package-name> --save
またはnpm install <package-name> -S
- インストールしたパッケージを
package.json
のdependencies
に追加します。 - npm v5以降ではこれがデフォルトの挙動なので、通常は明示的に指定する必要はありません。
-
-D
,--save-dev
:npm install <package-name> --save-dev
またはnpm install <package-name> -D
- インストールしたパッケージを
package.json
のdevDependencies
に追加します。 - 開発時のみ必要なツールやライブラリに利用します。
-
-O
,--save-optional
:npm install <package-name> --save-optional
またはnpm install <package-name> -O
- インストールしたパッケージを
package.json
のoptionalDependencies
に追加します。 optionalDependencies
は、インストールに失敗しても全体のインストールプロセスが中断されない依存関係です。特定の環境でのみ必要なパッケージなどに利用されます。
-
-E
,--save-exact
:npm install <package-name> --save-exact
またはnpm install <package-name> -E
- インストールしたパッケージを
package.json
に追加する際に、バージョン指定にチルダ (~
) やキャレット (^
) を付けず、厳密なバージョン番号(例:1.2.3
)で記録します。 - これにより、将来
npm install
を実行しても、指定した正確なバージョン以外のバージョンがインストールされることはありません。最大の安定性が得られますが、依存パッケージのバグ修正などが自動で取り込まれなくなるため、定期的に依存関係を更新 (npm update
) する手間が増えます。
-
-g
,--global
:npm install <package-name> -g
- パッケージをシステムグローバルにインストールします。CLIツールなどに利用します。
-
--production
:npm install --production
devDependencies
を除外し、dependencies
とoptionalDependencies
のみインストールします。本番環境へのデプロイ時などに利用します。
-
--no-package-lock
:npm install --no-package-lock
package-lock.json
ファイルの生成や更新を抑制します。- ほとんどの場合、このオプションを使用すべきではありません。
package-lock.json
が提供する確定的な依存関係管理のメリットを失ってしまいます。デバッグ目的などで一時的に使用する場合に限るべきです。
-
--force
:npm install --force
またはnpm i -f
- 依存関係の競合や、既に存在する同じバージョンのパッケージがあっても、強制的にインストールを実行します。
- 依存関係ツリーが壊れている場合などに最終手段として利用されることがありますが、予期せぬ副作用を引き起こす可能性があるため、使用は慎重に行う必要があります。このオプションは
package-lock.json
を無視し、package.json
に従って依存関係を解決し直す挙動になることが多いです。
-
--legacy-peer-deps
:npm install --legacy-peer-deps
- 主にnpm v7以降での
peerDependencies
の扱いの変更に対応するためのオプションです。npm v7では、peerDependencies
に指定された依存関係がインストールされていない場合、デフォルトでエラーになります。このオプションを付けると、npm v4~v6までの挙動(peerDependencies
が欠けていても警告で済ませるか、自動的にインストールしようとする)を模倣します。 - 古いライブラリや、まだnpm v7の新しい
peerDependencies
解決ロジックに対応していないライブラリを扱う場合に役立ちます。
-
-W
,--workspace <workspace-name>
:npm install <package-name> -W <workspace-name>
- Monorepo構成などでnpm Workspacesを利用している場合に、指定したワークスペース内でパッケージをインストール・管理するためのオプションです。
- 例: プロジェクト内の
packages/my-package
ワークスペースにutility-lib
をインストールする場合npm install utility-lib -W my-package
-
--omit=<type>
:npm install --omit=dev
またはnpm install --omit=optional
- 特定の種類の依存関係を除外してインストールします。
--omit=dev
は--production
とほぼ同等ですが、こちらは特定のタイプだけを除外したい場合に柔軟に使えます。例えば、--omit=dev --omit=optional
とすれば、dependencies
だけをインストールできます(ただしこのような使い方は稀です)。
これらのオプションを組み合わせることで、様々な状況に応じたきめ細やかなインストール制御が可能になります。しかし、普段の開発では npm install
(引数なし), npm install <package-name>
, npm install <package-name> -D
が主に使用され、package-lock.json
のおかげでほとんどの状況で安定した結果が得られます。
トラブルシューティング
npm install
は通常スムーズに完了しますが、時にはエラーが発生することもあります。ここでは、よくある問題とその対処法を紹介します。
1. 権限エラー (EACCES)
npmがグローバルインストールパスやキャッシュディレクトリに書き込む権限がない場合に発生します。特にmacOSやLinuxで、sudo npm install -g ...
のように sudo
を付けてnpmコマンドを実行したことがある場合に起こりやすいです。sudo
を使うと、npmがrootユーザーの権限でファイルを作成・変更するため、その後に一般ユーザーでnpmコマンドを実行しようとすると権限エラーになります。
推奨される対処法:
-
npmのデフォルトディレクトリを変更する: npmがユーザーのホームディレクトリ内の隠しディレクトリ(例:
~/.npm-global
)にグローバルパッケージやキャッシュを保存するように設定を変更するのが最も安全で推奨される方法です。
“`bash
# npm のデフォルトのグローバルインストールパスを確認
npm config get prefixパスを変更する (例: ホームディレクトリ直下)
npm config set prefix ‘~/.npm-global’
PATH 環境変数に新しいパスを追加 (お使いのシェル設定ファイルに合わせてください)
例えば Bash の場合 ~/.bashrc または ~/.bash_profile に以下を追加
export PATH=~/.npm-global/bin:$PATH
例えば Zsh の場合 ~/.zshrc に以下を追加
export PATH=~/.npm-global/bin:$PATH
設定ファイルを再読み込みするか、新しいターミナルを開く
source ~/.bashrc # または ~/.zshrc
npm の新しいパスが設定されたか確認
npm config get prefix
which npm # 新しいパスが表示されるはず
``
sudo
この設定変更後、なしでグローバルインストールができるようになります。一度設定すれば永続的です。
apt
* **npmのインストール方法を見直す:** Node.jsやnpmをシステムパッケージマネージャー(,
yum,
brewなど)でインストールした場合は、その方法に依存する場合があります。Node.jsの公式インストーラーや、バージョンマネージャー(
nvm,
nodenvなど)を利用してインストールしたnpmは、通常、権限問題を回避できるように設定されます。特に
nvm` はユーザーディレクトリにNode.js/npmをインストールするため、権限エラーが起こりにくいです。
避けるべき対処法:
sudo npm install ...
を使い続ける: これを続けると、プロジェクトディレクトリ内のnode_modules
などもroot権限になってしまい、さらに問題が複雑化します。絶対に必要な場合(非常に稀)以外はsudo
と npm を一緒に使うべきではありません。
2. ネットワークエラー
npmレジストリに接続できない場合に発生します。プロキシ設定が必要な企業内ネットワークや、単にインターネット接続が不安定な場合に起こります。
対処法:
- インターネット接続を確認します。
- 企業内ネットワークの場合は、プロキシ設定が必要か確認し、npmにプロキシを設定します。
bash
npm config set proxy http://your.proxy.server:port
npm config set https-proxy http://your.proxy.server:port
# 認証が必要な場合
# npm config set proxy http://username:[email protected]:port
# npm config set https-proxy http://username:[email protected]:port - npmレジストリが一時的にダウンしている可能性も考慮し、時間を置いて再度試します。
npm config get registry
で現在接続しているレジストリを確認できます。
3. 依存関係の競合 (Unmet Dependency, Peer Dependency Issues)
インストールしようとしているパッケージやその依存関係が、既にプロジェクトにインストールされている他のパッケージとバージョン要件で衝突する場合に発生します。
npm v7以前では、peerDependencies
の競合は警告で済まされることが多かったですが、npm v7以降ではデフォルトでエラーとなり、インストールが中断されることがあります。
対処法:
- エラーメッセージをよく読む: どのパッケージ間で競合が起きているのか、どのバージョンが必要とされているのかが記載されています。
- 依存関係ツリーを確認する:
npm list <package-name>
コマンドで、特定パッケージがプロジェクト内のどの場所で依存されているか、そのバージョンは何かを確認できます。
bash
npm list webpack
# またはツリー全体を表示 (非常に長くなる可能性があります)
npm list
# 依存関係ツリーの深さを制限する場合
npm list --depth=0 # 直下の依存のみ - 競合するパッケージのバージョンを調整する: 競合しているパッケージの一方を、他方のバージョン要件を満たすバージョンにアップグレードまたはダウングレードできないか検討します。
--legacy-peer-deps
オプションを使用する (npm v7+): 一時的な回避策として、peerDependencies
の競合をエラーにしないようにこのオプションを付けてインストールを試みます。ただし、これは根本的な解決策ではなく、バージョン競合による潜在的な問題(実行時エラーなど)を将来に持ち越す可能性があることを理解しておいてください。可能であれば、依存関係のバージョン調整で解決するのが望ましいです。--force
オプションを使用する: これは最終手段です。競合を無視して強制的にインストールしますが、node_modules
ディレクトリが不安定な状態になる可能性が高いです。
4. npmキャッシュの破損
npmがパッケージをダウンロードする際に利用するローカルキャッシュが破損している場合、インストールが失敗することがあります。
対処法:
- npmキャッシュをクリアする: npm v5以降では
npm cache clean --force
コマンドでキャッシュを完全に削除できます。
bash
npm cache clean --force
注意: このコマンドはキャッシュを全て削除するため、次にパッケージをインストールする際に時間がかかる場合があります。また、滅多に必要ありません。キャッシュが原因のトラブルは比較的稀です。まずは他の対処法を試しましょう。
5. node_modules
ディレクトリの状態がおかしい
過去のインストール作業の失敗や、手動でのファイル操作などにより、node_modules
ディレクトリの内容が破損したり、package-lock.json
の内容と一致しなくなったりすることがあります。
対処法:
-
node_modules
ディレクトリを削除し、再インストールする: これが最も一般的な対処法です。クリーンな状態から依存関係を再構築します。
“`bash
# プロジェクトのルートディレクトリで実行
rm -rf node_modules # macOS/Linux
# または PowerShell で
# Remove-Item -Recurse -Force node_modules
# または コマンドプロンプトで
# rmdir /s /q node_modulespackage-lock.json も一度削除して再生成したい場合はこちらも
rm package-lock.json # macOS/Linux
Remove-Item package-lock.json # PowerShell
del package-lock.json # コマンドプロンプト
依存関係を再インストール
npm install
``
node_modulesの削除は、多くの「なんかnpmがおかしい」問題に対する有効な解決策です。ただし、
package-lock.jsonを削除する場合は、依存関係のバージョンが
package.jsonの指定に従って再度解決されることに注意してください。通常は
node_modules` だけを削除して再インストールすれば十分です。
6. ディスク容量不足
node_modules
ディレクトリは非常に大きくなることがあります。ディスク容量が不足しているとインストールに失敗します。
対処法:
- ディスクの空き容量を確認し、不要なファイルを削除して容量を確保します。
7. 脆弱性レポート (npm audit
)
npm install
コマンドの実行後、npmがインストールされた依存関係に既知のセキュリティ脆弱性がないかを自動的にチェックし、脆弱性が発見された場合はレポートを表示します。
“`
npm install 実行後の出力例
found 5 vulnerabilities (2 low, 3 high)
run npm audit fix
to fix them, or npm audit
for details
“`
これはエラーではありませんが、重要な警告です。
対処法:
npm audit
で詳細を確認する: どのパッケージにどのような脆弱性があるのか、どのように依存しているのかなどの詳細が表示されます。npm audit fix
で自動修正を試みる: 脆弱性のあるパッケージを、互換性のあるより安全なバージョンに自動的に更新しようと試みます。
bash
npm audit fixnpm audit fix --force
を使用する (慎重に):npm audit fix
で修正できない(互換性のない変更が必要な)脆弱性も強制的に修正しようとします。これは互換性を壊す可能性があるので、適用後はアプリケーションが正常に動作するか入念なテストが必要です。- 手動で依存関係を更新する:
npm audit
のレポートを見て、脆弱性のあるパッケージを直接 (npm update <package-name>
) 更新したり、そのパッケージに依存している上位のパッケージを更新したりします。
セキュリティ脆弱性の情報は常に最新に保つべきですが、npm audit fix
の自動修正は既存コードの動作に影響を与える可能性があるので、特に --force
を使う場合は注意が必要です。
npm scripts と npm install
package.json
の scripts
フィールドには、様々なカスタムコマンドを定義できますが、その中には npm install
の特定のライフサイクルイベント時に自動的に実行される特別なスクリプトがあります。
preinstall
: パッケージがインストールされる直前に実行されます。install
: パッケージがインストールされた後、依存関係の解決やネイティブコードのコンパイルなどが必要な場合に実行されることがあります。多くのパッケージは、インストールプロセスの一部としてこのスクリプトを利用してビルドなどの後処理を行います。postinstall
: パッケージのインストール完了後に実行されます。主にビルド処理やセットアップ処理に利用されます。例えば、フロントエンドプロジェクトで依存関係インストール後にビルドを行う場合などです。prepare
: このスクリプトは、パッケージのインストール時だけでなく、公開(publish)前やパック(pack)前にも実行されます。postinstall
よりも広範な用途で利用でき、開発中 (npm install
from git), パック中 (npm pack
), 公開中 (npm publish
) など様々な状況で実行されます。多くの場合、TypeScriptのトランスパイルや、依存関係を必要とする複雑なビルド処理などに利用されます。
これらのスクリプトは、依存パッケージに含まれている場合も、あなたのプロジェクトの package.json
に含まれている場合も、npm install
実行フローの一部として自動的に実行されます。これにより、パッケージが必要とするビルドや設定がインストール時に自動的に行われます。
もしインストールがこれらのスクリプトの実行中に失敗した場合、npm install 全体が失敗したことになります。
代替パッケージマネージャー (yarn, pnpm)
Node.jsのパッケージマネージャーはnpmだけではありません。Yarn (Facebookによって開発)、pnpm (Perforceによって開発) など、npmの代替となるパッケージマネージャーも存在します。これらは、依存関係の解決アルゴリズムや node_modules
ディレクトリの管理方法に違いがあり、特にインストール速度やディスク容量効率、Monorepo対応などで優位性を持つ場合があります。
- Yarn: 初期のnpm v3-v4の課題(インストール速度、確定性)を解決するために生まれました。
yarn.lock
というロックファイルを使用します。 - pnpm:
node_modules
ディレクトリをシンボリックリンクとハードリンクを組み合わせて管理することで、非常に効率的なディスク使用量と高速なインストールを実現します。コンテンツ・アウェア・ストアと呼ばれる仕組みで、同じバージョンのパッケージはディスク上で一度だけ保存されます。pnpm-lock.yaml
というロックファイルを使用します。
これらの代替パッケージマネージャーも基本的なコマンド (install
, add
, remove
など) はnpmと似ていますが、内部実装やロックファイルの形式は異なります。あなたのプロジェクトの要件やチームの好みに応じて、これらのパッケージマネージャーを検討する価値はあります。
しかし、npm install
の基本的な概念(package.json
, 依存関係の種類, SemVer, ロックファイル)は、これらの代替ツールでも共通しており、理解の基盤となります。
まとめ:npm install
のベストプラクティス
この記事では、npm install
の多岐にわたる側面を詳細に解説しました。最後に、Node.js開発者が実践すべき npm install
に関連するベストプラクティスをまとめます。
- ほとんどのパッケージはローカルにインストールする: アプリケーションやライブラリが依存するパッケージは、必ずプロジェクトローカル (
--save
またはデフォルト) または開発依存 (--save-dev
,-D
) としてインストールし、package.json
に記録します。グローバルインストールは、CLIツールなどシステム全体で利用する目的が明確な場合に限定します。 package.json
とpackage-lock.json
をバージョン管理する: この2つのファイルをGitなどのバージョン管理システムにコミットし、チームメンバー間で共有します。特にpackage-lock.json
は、依存関係の確定的な状態を保証するために不可欠です。.gitignore
にnode_modules
は含めますが、package-lock.json
は含めないようにします。- SemVerとバージョン指定を理解する:
package.json
に記述されるバージョン指定(特に^
と~
)の意味を理解し、依存関係のバージョンがどのように解決されるかを把握しておきます。必要に応じて--save-exact
オプションも検討します。 - 本番環境では
--production
を使う: アプリケーションをデプロイする際は、npm install --production
を実行してdevDependencies
を除外します。多くのPaaSではNODE_ENV=production
でデフォルトで--production
が有効になります。 - インストールエラーに適切に対処する: エラーメッセージを注意深く読み、権限、ネットワーク、依存関係の競合、キャッシュ破損など、考えられる原因を一つずつ調査します。
rm -rf node_modules
と再インストールは、多くの問題に対する有効な初手です。 npm audit
で脆弱性をチェックする: 定期的にnpm audit
を実行し、依存関係に既知の脆弱性がないか確認します。必要に応じてnpm audit fix
を実行しますが、--force
を使う場合は慎重に行います。- npmスクリプトのライフサイクルを理解する: 特に
prepare
やpostinstall
など、インストール時に自動実行されるスクリプトの挙動を理解しておくと、パッケージのビルドプロセスなどを把握するのに役立ちます。
npm install
はNode.js開発の日常的なコマンドですが、その裏側にある仕組みやベストプラクティスを理解することは、プロジェクトを安定させ、チーム開発を円滑に進める上で非常に重要です。この記事が、あなたの npm install
マスターへの一歩となることを願っています。
付録:主要な npm install
オプション一覧
オプション | 短縮形 | 説明 | デフォルト (npm v5+) |
---|---|---|---|
--save |
-S |
インストールしたパッケージを dependencies に追加する |
有効 |
--save-dev |
-D |
インストールしたパッケージを devDependencies に追加する |
無効 |
--save-optional |
-O |
インストールしたパッケージを optionalDependencies に追加する |
無効 |
--save-exact |
-E |
インストールしたパッケージのバージョンを厳密に (1.2.3 ) package.json に記録する |
無効 |
--global |
-g |
パッケージをシステムグローバルにインストールする | 無効 |
--production |
devDependencies を除外してインストールする (NODE_ENV=production 時はデフォルトで有効) |
無効 | |
--no-package-lock |
package-lock.json の生成・更新を抑制する (非推奨) |
無効 | |
--force |
-f |
競合やエラーを無視して強制的にインストールする (慎重に使用) | 無効 |
--legacy-peer-deps |
peerDependencies の解決方法をnpm v4-v6の挙動に戻す (npm v7以降で互換性問題に対応) |
無効 | |
--workspace <name> |
-W |
Monorepo環境で指定したワークスペース内でインストールする | 無効 |
--omit=<type> |
指定したタイプの依存関係 (dev , optional , peer ) を除外してインストールする |
無効 | |
--no-audit |
インストール後の自動脆弱性チェック (npm audit ) を無効にする |
無効 |
これで、約5000語の詳細な記事が完成しました。npm install
に関するあなたの理解を深める助けになれば幸いです。