CLOVER🍀

That was when it all began.

npm installとnpm ciの違いをメモする

これは、なにをしたくて書いたもの?

Node.jsでモジュールをインストールするコマンドとしてnpm install(エイリアスnpm i、npm add)があるわけですが、
npm ciがどういうものだったかよく忘れるのでメモしておきます。

ちょっとドキュメントを眺めてみましょう。

環境

今回の環境は、こちら。

$ node --version
v16.13.1


$ npm --version
8.1.2

というわけで、npm v8のドキュメントを見ていきます。

npm ci

npm ciのドキュメントはこちら。

npm-ci | npm Docs

npm ciは、npm installに似たコマンドです。CI環境やテスト環境での利用、依存関係のクリーンインストールを行う場合に
使用します。

特徴は、以下です。

  • プロジェクトはpackage-lock.jsonはnpm-shrinkwrap.jsonのどちらかを保持している必要がある
  • package.jsonと、package-lock.json(またはnpm-shrinkwrap.json)の間に一致しない依存関係がある場合、npm ciは失敗する
    • npm installは、このパターンではpackage-lock.jsonを更新する
  • プロジェクト全体の依存関係がインストール可能で、個別の依存関係を追加は不可
  • node_modulesディレクトリが存在する場合は、npm ciの実行前に自動的に削除される
  • package.jsonやpackage-lock.jsonファイルへの更新は行われず、インストール対象のパッケージバージョンは凍結される

npm install

npm installのドキュメントは、こちら。

npm-install | npm Docs

npm installは、以下のファイルの優先順位に従って動作します。

  • npm-shrinkwrap.json
  • package-lock.json
  • yarn.lock
npm install [パッケージ]

1番よく使うものかなと。パッケージについてはこちらに書かれており、npmレジストリに存在するもの以外に、
tar.gzやフォルダも使えることになっています。

About packages and modules / About packages

このコマンドは、指定されたパッケージをローカルのnode_modulesディレクトリにインストールします。

以下の指定方法では、latestタグに相当するバージョンがインストールされ、dependencies(-Dまたは--save-devを
使った場合はdevDependencies)に追加されます。

$ npm install [<@scope>/]<name>

この時、package-lock.jsonも更新されます。

その他の指定パターン(※)については、ドキュメントを参照…。

※このあたりですね

  • npm install [<@scope>/]<name>@<version>
  • npm install [<@scope>/]<name>@<version range>
  • npm install [<@scope>/]<name>@<tag>
  • npm install [Git URL、GitHub、BitBucket等]
npm install(引数なし)

依存関係をローカルのnode_modulesディレクトリにインストールします。
※-gまたは--globalオプションが付与されている場合は、カレントディレクトリをグローバルとして扱ってインストール

デフォルトでは、package.jsonに記述されているすべての依存関係がインストールされます。

--productionオプションまたは環境変数NODE_ENVにproductionが設定されている場合は、devDependenciesに
記述されている依存関係はインストールされません。

NODE_ENV環境変数をproductionに設定している場合でもdependenciesとdevDependenciesの両方をインストールする
場合は、--production=falseとオプションに指定すればよいみたいです。

ちなみに、--productionオプションは依存関係の追加時には効果がありません。

--production flag has no particular meaning when adding a dependency to a project.`

npm install [ディレクトリ]

現在のプロジェクトへのシンボリックリンクとして、パッケージをインストールします。
対象のパッケージに依存関係がある場合は、シンボリックリンク作成前にインストールされます。

npm install [tarファイル]

ファイルシステム上にあるパッケージをインストールします。

ちょっと試してみる

簡単に試してみましょう。

Node.jsプロジェクトを作成して

$ npm init -y

以下の依存関係をインストール。

$ npm i -D typescript
$ npm i -D -E prettier
$ npm i -D jest @types/jest ts-jest
$ npx ts-jest config:init
$ npm i express
$ npm i -D @types/node@v16 @types/express

こうなります。

$ ll package*.json
-rw-rw-r-- 1 xxxxx xxxxx 310127  1月  4 15:56 package-lock.json
-rw-rw-r-- 1 xxxxx xxxxx    582  1月  4 15:56 package.json

依存関係は、これだけですね。

  "devDependencies": {
    "@types/express": "^4.17.13",
    "@types/jest": "^27.4.0",
    "@types/node": "^16.11.18",
    "jest": "^27.4.5",
    "prettier": "2.5.1",
    "ts-jest": "^27.1.2",
    "typescript": "^4.5.4"
  },
  "dependencies": {
    "express": "^4.17.2"
  }

npm lsで確認。

$ npm ls
project@1.0.0 /path/to/project
├── @types/express@4.17.13
├── @types/jest@27.4.0
├── @types/node@16.11.18
├── express@4.17.2
├── jest@27.4.5
├── prettier@2.5.1
├── ts-jest@27.1.2
└── typescript@4.5.4

1度、node_modulesディレクトリを削除します。

$ rm -rf node_modules

npm i(npm install)。

$ npm i

依存関係は変わっていませんが、package-lock.jsonは更新されます。

$ npm ls
project@1.0.0 /path/to/project
├── @types/express@4.17.13
├── @types/jest@27.4.0
├── @types/node@16.11.18
├── express@4.17.2
├── jest@27.4.5
├── prettier@2.5.1
├── ts-jest@27.1.2
└── typescript@4.5.4


$ ll package*.json
-rw-rw-r-- 1 xxxxx xxxxx 310127  1月  4 16:34 package-lock.json
-rw-rw-r-- 1 xxxxx xxxxx    582  1月  4 15:56 package.json

npm ciを実行してみます。

$ npm ci

こちらは、package-lock.jsonは更新されません。

$ npm ls
project@1.0.0 /path/to/project
├── @types/express@4.17.13
├── @types/jest@27.4.0
├── @types/node@16.11.18
├── express@4.17.2
├── jest@27.4.5
├── prettier@2.5.1
├── ts-jest@27.1.2
└── typescript@4.5.4


$ ll package*.json
-rw-rw-r-- 1 xxxxx xxxxx 310127  1月  4 16:34 package-lock.json
-rw-rw-r-- 1 xxxxx xxxxx    582  1月  4 15:56 package.json

npm ciにも--productionは指定できるみたいですね。

$ npm ci --production

npm lsすると、devDependenciesの分は不足扱いになってしまいますが。

$ npm ls
project@1.0.0 /path/to/project
├── UNMET DEPENDENCY @types/express@^4.17.13
├── UNMET DEPENDENCY @types/jest@^27.4.0
├── UNMET DEPENDENCY @types/node@^16.11.18
├── express@4.17.2
├── UNMET DEPENDENCY jest@^27.4.5
├── UNMET DEPENDENCY prettier@2.5.1
├── UNMET DEPENDENCY ts-jest@^27.1.2
└── UNMET DEPENDENCY typescript@^4.5.4

npm ERR! code ELSPROBLEMS
npm ERR! missing: @types/express@^4.17.13, required by npm-ci-test@1.0.0
npm ERR! missing: @types/jest@^27.4.0, required by npm-ci-test@1.0.0
npm ERR! missing: @types/node@^16.11.18, required by npm-ci-test@1.0.0
npm ERR! missing: jest@^27.4.5, required by npm-ci-test@1.0.0
npm ERR! missing: prettier@2.5.1, required by npm-ci-test@1.0.0
npm ERR! missing: ts-jest@^27.1.2, required by npm-ci-test@1.0.0
npm ERR! missing: typescript@^4.5.4, required by npm-ci-test@1.0.0

npm ERR! A complete log of this run can be found in:
npm ERR!     $HOME/.npm/_logs/2022-01-04T07_39_03_323Z-debug.log

もう1度、node_modulesディレクトリを削除。

$ rm -rf node_modules

npm install。

$ npm i


$ npm ls
project@1.0.0 /path/to/project
├── @types/express@4.17.13
├── @types/jest@27.4.0
├── @types/node@16.11.18
├── express@4.17.2
├── jest@27.4.5
├── prettier@2.5.1
├── ts-jest@27.1.2
└── typescript@4.5.4

npm install --productionでも、ここからdependenciesのみの状態にできるようですが

$ npm i --production


$ npm ls
project@1.0.0 /path/to/project
├── UNMET DEPENDENCY @types/express@^4.17.13
├── UNMET DEPENDENCY @types/jest@^27.4.0
├── UNMET DEPENDENCY @types/node@^16.11.18
├── express@4.17.2
├── UNMET DEPENDENCY jest@^27.4.5
├── UNMET DEPENDENCY prettier@2.5.1
├── UNMET DEPENDENCY ts-jest@^27.1.2
└── UNMET DEPENDENCY typescript@^4.5.4

npm ERR! code ELSPROBLEMS
npm ERR! missing: @types/express@^4.17.13, required by npm-ci-test@1.0.0
npm ERR! missing: @types/jest@^27.4.0, required by npm-ci-test@1.0.0
npm ERR! missing: @types/node@^16.11.18, required by npm-ci-test@1.0.0
npm ERR! missing: jest@^27.4.5, required by npm-ci-test@1.0.0
npm ERR! missing: prettier@2.5.1, required by npm-ci-test@1.0.0
npm ERR! missing: ts-jest@^27.1.2, required by npm-ci-test@1.0.0
npm ERR! missing: typescript@^4.5.4, required by npm-ci-test@1.0.0

npm ERR! A complete log of this run can be found in:
npm ERR!     $HOME/.npm/_logs/2022-01-04T07_46_41_347Z-debug.log

やっぱりpackage-lock.jsonは更新されます。

$ ll package*.json
-rw-rw-r-- 1 xxxxx xxxxx 310127  1月  4 16:47 package-lock.json
-rw-rw-r-- 1 xxxxx xxxxx    582  1月  4 15:56 package.json

というわけで、単にプロジェクトで定義されている依存関係をインストールしたいだけなら、npm ciを使った方が
よい感じがしますね。