dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

npm installしたパッケージの更新確認とアップデート(npm-check-updates)

タイトルの通り。
npm install --save なり --save-dev なりして package.json に書き込まれたパッケージのバージョン、どうやって定期的にアップデートしていけばいいかわからなかったので。

新しいバージョンがリリースされているかどうかの確認と、実際にどのように新しいバージョンにアップデートすればいいのか調べてみた。

今回サンプルに使う package.json

package.json の例として、以前、React のチュートリアルをやったときのリポジトリを使う。

{
  "name": "react-es6-tutorial",
  "version": "1.0.0",
  "description": "React Tutorial written in ES6",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint src/**/*.js",
    "webpack": "webpack -w",
    "start": "concurrent \"npm run webpack\" \"npm run lite\""
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.7.2",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-react": "^6.5.0",
    "concurrently": "^2.0.0",
    "eslint": "^2.9.0",
    "eslint-config-airbnb": "^9.0.1",
    "eslint-plugin-import": "^1.8.0",
    "eslint-plugin-jsx-a11y": "^1.2.0",
    "eslint-plugin-react": "^5.1.1",
    "webpack": "^1.12.14"
  },
  "dependencies": {
    "jquery": "^2.2.2",
    "marked": "^0.3.5",
    "react": "^0.14.7",
    "react-dom": "^0.14.7"
  }
}

この package.json に記載された通りのバージョン(babel-core なら 6.7.2)がインストールされた状態、という前提で話を進める。


現在インストールされているバージョンを確認する方法

そもそも、現在インストールされているバージョンを確認するにはどうしたらいいのか。
これは、後述する npm outdated コマンドを使うこともできるが、別の方法として

$ npm list --depth=0

コマンドを使うという方法もある。

$ npm list --depth=0
react-es6-tutorial@1.0.0 /Users/yamazaki/workspace/react/react-tutorial
├── babel-core@6.7.2
├── babel-loader@6.2.4
├── babel-preset-es2015@6.6.0
├── babel-preset-react@6.5.0
├── concurrently@2.0.0
├── eslint@2.9.0
├── eslint-config-airbnb@9.0.1
├── eslint-plugin-import@1.8.0
├── eslint-plugin-jsx-a11y@1.2.0
├── eslint-plugin-react@5.1.1
├── jquery@2.2.2
├── marked@0.3.5
├── react@0.14.7
├── react-dom@0.14.7
└── webpack@1.12.14

後述する npm outdated はバージョンが古くなったパッケージしか表示されないのに対し、
こちらはインストール済みのすべてのパッケージの情報が出力できる。


最新バージョンがあるかどうか確認する方法

インストールしたパッケージに新しいバージョンが存在するかどうか、確認する。
これは、

$ npm outdated

を使う。
https://docs.npmjs.com/cli/outdated

このコマンドを実行すると、以下のような結果が出力される。

f:id:dackdive:20161009200339p:plain

$ npm outdated
Package                 Current  Wanted  Latest  Location
babel-core                6.7.2  6.17.0  6.17.0  babel-core
babel-loader              6.2.4   6.2.5   6.2.5  babel-loader
babel-preset-es2015       6.6.0  6.16.0  6.16.0  babel-preset-es2015
babel-preset-react        6.5.0  6.16.0  6.16.0  babel-preset-react
concurrently              2.0.0   2.2.0   3.1.0  concurrently
eslint                    2.9.0  2.13.1   3.7.1  eslint
eslint-config-airbnb      9.0.1   9.0.1  12.0.0  eslint-config-airbnb
eslint-plugin-import      1.8.0  1.16.0   2.0.0  eslint-plugin-import
eslint-plugin-jsx-a11y    1.2.0   1.5.5   2.2.2  eslint-plugin-jsx-a11y
eslint-plugin-react       5.1.1   5.2.2   6.3.0  eslint-plugin-react
jquery                    2.2.2   2.2.4   3.1.1  jquery
marked                    0.3.5   0.3.6   0.3.6  marked
react                    0.14.7  0.14.8  15.3.2  react
react-dom                0.14.7  0.14.8  15.3.2  react-dom
webpack                 1.12.14  1.13.2  1.13.2  webpack

各パッケージに対し、Current, Wanted, Latest という3つの列が表示されている。
それぞれの列の意味は以下の通り。

Current

現在インストールされているバージョン

Wanted

存在するバージョンのうち、package.json に記載された semver の条件を満たす最新のバージョン。
たとえば、jQuery については

Package                 Current  Wanted  Latest  Location
jquery                    2.2.2   2.2.4   3.1.1  jquery

となっているが、これは 2.x 系の最新は 2.2.4 がリリースされており、それよりメジャーバージョンが1つ上の 3.x 系で 3.1.1 がリリースされている。
ただし、package.json^2.2.2 という記述では

2.2.2 <= n < 3.0.0

という範囲での最新バージョンしか許容されないため、Wanted は 3.x 系ではなく 2.x 系の最新バージョンとなる。

^2.2.2 という記述については以前ブログに書いた。
package.jsonのパッケージバージョンに記載される ^ (キャレット) とは?どうしてつくのか? - dackdive's blog


Latest

npm outdated のドキュメント によると

latest is the version of the package tagged as latest in the registry.

とあるが、そのパッケージの最新バージョンと考えてよさそう。


npm outdated の問題点

さて、この状態で npm update を実行し、再度 npm outdated で結果を確認してみる。

$ npm update
npm WARN peerDependencies The peer dependency react@^0.14.8 included from react-dom will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
marked@0.3.6 node_modules/marked
babel-loader@6.2.5 node_modules/babel-loader

...(略)


$ npm outdated
Package                 Current  Wanted  Latest  Location
concurrently              2.2.0   2.2.0   3.1.0  concurrently
eslint                   2.13.1  2.13.1   3.7.1  eslint
eslint-config-airbnb      9.0.1   9.0.1  12.0.0  eslint-config-airbnb
eslint-plugin-import     1.16.0  1.16.0   2.0.0  eslint-plugin-import
eslint-plugin-jsx-a11y    1.5.5   1.5.5   2.2.3  eslint-plugin-jsx-a11y
eslint-plugin-react       5.2.2   5.2.2   6.3.0  eslint-plugin-react
jquery                    2.2.4   2.2.4   3.1.1  jquery
react                    0.14.8  0.14.8  15.3.2  react
react-dom                0.14.8  0.14.8  15.3.2  react-dom

babel-core などのパッケージは最新の 6.17.0 にアップデートされたため、表示されなくなった。

ただし、ESLint などについてはメジャーバージョンが上がったものがリリースされているが、npm update は package.json に記載された semver のルールに従うため、^ つきの記載だとメジャーバージョンのアップデートまでは行ってくれない。

また、npm outdated は パッケージの更新確認はやってくれるが、package.json の更新まではやってくれない という問題もある。
そのため、

  • npm outdated で新しいバージョンがリリースされてないか確認する
  • 新しいバージョンがリリースされていた場合、該当のパッケージを package.json から削除する
  • npm install --save/--save-dev で再度インストールする

という手順になってしまい、ややめんどくさい。
どうするか。


npm-check-updates を使う

というわけで色々調べていると、更新確認とアップデートに便利な npm-check-updates というパッケージを見つけた。

npm-check-updates は

$ npm install -g npm-check-updates

というようにグローバルにインストールする。インストールすると

$ ncu

というコマンドが使えるようになる。

ncu を実行してみる。

$ ncu
⸨░░░░░░░░░░░░░░░░░░⸩ ⠦ :
 jquery                   ^2.2.2  →   ^3.1.1
 react                   ^0.14.7  →  ^15.3.2
 react-dom               ^0.14.7  →  ^15.3.2
 concurrently             ^2.0.0  →   ^3.1.0
 eslint                   ^2.9.0  →   ^3.7.1
 eslint-config-airbnb     ^9.0.1  →  ^12.0.0
 eslint-plugin-import     ^1.8.0  →   ^2.0.0
 eslint-plugin-jsx-a11y   ^1.2.0  →   ^2.2.3
 eslint-plugin-react      ^5.1.1  →   ^6.4.0

The following dependencies are satisfied by their declared version range, but the installed versions are behind. You can install the latest versions without modifying your package file by using npm update. If you want to update the dependencies in your package file anyway, use ncu -a/--upgradeAll.

 marked                 ^0.3.5  →   ^0.3.6
 babel-core             ^6.7.2  →  ^6.17.0
 babel-loader           ^6.2.4  →   ^6.2.5
 babel-preset-es2015    ^6.6.0  →  ^6.16.0
 babel-preset-react     ^6.5.0  →  ^6.16.0
 webpack              ^1.12.14  →  ^1.13.2

Run ncu with -u to upgrade package.json

内容としては npm outdated を実行したときと同じ。
上部(The following... より上に列挙されているもの)は、新しいメジャーバージョンがリリースされているもの。
下部はマイナーバージョン以下で新しいバージョンが存在するもの。The following... の文章に書いてあるとおり、こちらは npm update すれば最新のバージョンがインストールできる。

そして、ncu に -u オプションをつけると package.json の更新が行われる。

$ ncu -u

...

Upgraded /Users/yamazaki/workspace/react/react-tutorial/package.json

$ git diff package.json
diff --git a/package.json b/package.json
index 11e9a27..f3e6979 100644
--- a/package.json
+++ b/package.json
@@ -17,18 +17,18 @@
     "babel-loader": "^6.2.4",
     "babel-preset-es2015": "^6.6.0",
     "babel-preset-react": "^6.5.0",
-    "concurrently": "^2.0.0",
-    "eslint": "^2.9.0",
-    "eslint-config-airbnb": "^9.0.1",
-    "eslint-plugin-import": "^1.8.0",
-    "eslint-plugin-jsx-a11y": "^1.2.0",
-    "eslint-plugin-react": "^5.1.1",
+    "concurrently": "^3.1.0",
+    "eslint": "^3.7.1",
+    "eslint-config-airbnb": "^12.0.0",
+    "eslint-plugin-import": "^2.0.0",
+    "eslint-plugin-jsx-a11y": "^2.2.3",
+    "eslint-plugin-react": "^6.4.0",
     "webpack": "^1.12.14"
   },
   "dependencies": {
-    "jquery": "^2.2.2",
+    "jquery": "^3.1.1",
     "marked": "^0.3.5",
-    "react": "^0.14.7",
-    "react-dom": "^0.14.7"
+    "react": "^15.3.2",
+    "react-dom": "^15.3.2"
   }
 }

package.json の更新が正しく行われた。

なお、ncu コマンドは

$ ncu -u [パッケージ名]

というようにパッケージ名を指定することができる。さらに、パッケージ名の部分には正規表現を使用することができる。

# babel-xxx というパッケージのみ対象
$ ncu /babel-/
⸨░░░░░░░░░░░░░░░░░░⸩ ⠏ :
The following dependencies are satisfied by their declared version range, but the installed versions are behind. You can install the latest versions without modifying your package file by using npm update. If you want to update the dependencies in your package file anyway, use ncu -a/--upgradeAll.

 babel-core           ^6.7.2  →  ^6.17.0
 babel-loader         ^6.2.4  →   ^6.2.5
 babel-preset-es2015  ^6.6.0  →  ^6.16.0
 babel-preset-react   ^6.5.0  →  ^6.16.0


また、ncu -c だと babel-core などマイナーバージョン以下がアップデートされたパッケージについては package.json は更新されなかったが、

$ ncu -a

というように、-u のかわりに -a オプションをつけて実行すると、これらのパッケージについても package.json が更新される。


注意点

npm-check-updates は package.json の更新のみ行い、実際のアップデートは行われていないので注意。
ncu -u した後 npm update する必要がある。


リファレンス