term タグ別の記事一覧

npmで「npm install -g」ではなくnpxをおすすめする理由

npmではライブラリだけでなく、Node.jsで実装されたコマンドラインツールも多数配布されています。こういったツールをインストールする際に「npm install -g」のように-gオプション付きでnpm installコマンドを実行すると、そのコマンドがパスの通った場所にインストールされ、カレントディレクトリがどのディレクトリであってもコマンド名だけでそのコマンドを実行できるようになります。

たとえばこの方法でvueコマンド(vue-cli)をインストールする場合、次の例のようになります。

# npm intall -g @vue/cli

こうやってインストールすると、次のようにvueコマンドだけでvue-cliを実行可能になります。

$ vue

この方法は一見便利なように見えますが、npm install -gコマンドの実行時にroot権限が必要になるという問題があります。さらに、インストールしたコマンドは全ユーザーが利用できるようになるため、意図せずに他のコマンドと競合するといった副作用が発生する可能性もあります。

そのためおすすめしたいのが、-gコマンドを利用せずにローカルディレクトリにインストールし、npxコマンドを使ってインストールしたコマンドラインツールを利用するというやり方です。

npxコマンドは、カレントディレクトリを起点としてnode_modulesディレクトリを探索し、引数で指定したコマンドを見つけたらそれを実行する、という処理を行うコマンドで、2017年にリリースされたnpm v5.2.0からnpmに同梱されています(リリースノート)。

たとえば先のvue-cliを利用したい場合、まずこのツールを利用したいプロジェクトのディレクトリ内で次のように-gオプションなしでインストールを行います(ちなみに-DはインストールするモジュールをdevDependenciesに追加する処理を行うオプションです)。

$ npm install -D @vue/cli

こうやってインストールしたvueコマンドを使って、たとえば「vue create」コマンドを実行したい場合、次のように実行します。

$ npx vue create .

ちなみにここではプロジェクト名の代わりに「.」を指定していますが、こうするとvue-cliはカレントディレクトリ内にプロジェクトを作成してくれます。

この手法には、root権限が不要であるというだけでなく、プロジェクトごとに異なるバージョンのツールを簡単に利用できるようになるというメリットもあります。一方でデメリットとしては、プロジェクトごとにインストールが必要になり、またそのためディスク容量を余分に使用するというものがあります。とは言え、昨今のツールでそのデメリットはあまり大きくないでしょう。

ここではvueコマンドを例にしましたが、tscコマンドやwebpack-cliなどでも同様に使えます。

Node.js 4.xで廃止となったutil.is系メソッドの代替案

Node.jsの最新長期サポート版(LTS)であるv4.3.0では、それまで利用できたutil.isArray()やutil.isRegExp()、util.isDate()などのメソッドがDeprecated(廃止予定)扱いとなっています(v4.x系のドキュメントv0.12.x系のドキュメント)。

ドキュメントには理由が説明されておらず、代替案も掲載されていないのですが、StackOverflowでの情報によると、「後方互換性がなくなるために修正したくないから」だそうです。例としてutil.isObject()に関数オブジェクトを与えると戻り値はfalseになりますが、JavaScript(ECMAScript)の言語仕様上は関数オブジェクトもオブジェクトであり、これは不適切な実装であることが挙げられています。

isArrayとかisStringとかはあっても良いのでは……と思いますが、まあほかのコードで代替可能なのでコアからは削除する、というのは理解できます。ということで代替案ですが、下記のようにisinstanceof演算子で代替できます。

$ node
> [] instanceof Array
true
> [] instanceof Object
true
> [] instanceof String
false

なお面倒臭いことに、instanceof演算子はプリミティブ型(文字列や数値型など、オブジェクトではないもの)に対してはすべてfalseを返します。そのため、プリミティブ型に対してはtypeof演算子の戻り値を使用して判断する必要があります。

> typeof a
'string'
> typeof []
'object'
> typeof 10.1
'number'
> typeof /ABC/
'object'