話題の記事

知らないのは損!npmに同梱されているnpxがすごい便利なコマンドだった

Nodeのパッケージマネージャーであるnpmにはnpxというコマンドが同梱されています。これまであまり使ってこなかったのですが、調べてみたらとても便利なコマンドだったので使い方などをお届けします。
2019.08.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。サービスグループの武田です。

Nodeは現代のフロントエンド開発にはなくてはならない存在となりました。またクラスメソッド社内で静かなブームとなっているAWS CDKでの開発もNodeを利用します。そのCDKプロジェクトのひな型を作成する際に、npxコマンドを使用している例をよく見かけたのですが、そういえばこのコマンドよく知らないな?ということで調べてみました。

検証環境

次の環境で検証しています。

$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14.5
BuildVersion:	18F132

$ node -v
v10.16.3

$ npm -v
6.9.0

npx is 何

npxはnpmパッケージを簡単に実行できるコマンドです。具体的には次のようなことができます。

  • run-scriptを使用せずにローカルインストールしたコマンドを実行する
  • グローバルインストールせずに一度だけコマンドを実行する
  • GitHubやGistで公開されているスクリプトを実行する

npxはnpm@5.2.0から同梱されるようになった新しいコマンドです。Node@8.2以降を使用している環境であればデフォルトでインストールされているはずです。それより古い環境であっても、npm install -g npxでインストールできます。新しいと言ってもnpm@5.2.0のリリースは2017年7月なのでもう2年前ですね……。

Release v5.2.0 (2017-07-05) · npm/npm

用途についてそれぞれ見ていきます。

run-scriptを使用せずにローカルインストールしたコマンドを実行する

簡潔に

ローカルインストールしたパッケージを、設定なしで次のように実行できます。

$ mkdir /path/to/project && cd $_ && npm init -y

$ npm install cowsay

$ npx cowsay 'まどか'
 ________
< まどか >
 --------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

詳しく

npmパッケージはグローバル/ローカルのいずれかにインストールして使います。グローバルには独立したコマンドとして使いたい場合にインストールします。mochacreate-react-appなどが代表的でしょうか。ローカルにはプログラム内でrequireして使いたいモジュールや、そのプロジェクト固有のパッケージをインストールします。lodashreactなど、挙げ始めたらきりがないですね。

さて先述したようにnpmパッケージにはCLIのコマンドを提供するものがあります。実はパッケージがコマンドを提供していれば、グローバル/ローカルのインストールにかかわらず実行可能です。ただローカルにインストールした場合、それがやや面倒だったという背景がありました。

ローカルインストールしたパッケージは、そのプロジェクトのnode_modules配下にインストールされます。そしてコマンドが提供されている場合、node_modules/.bin/配下にコマンドが配置されます。そのため次のように実行することになります。

$ npm list --depth 0
project@1.0.0 /path/to/project
└── cowsay@1.4.0

$ ./node_modules/.bin/cowsay 'ほむら'
 ________
< ほむら >
 --------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

$ $(npm bin)/cowsay 'さやか'
 ________
< さやか >
 --------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

npm binはカレントプロジェクトのローカルパッケージPATHを返してくれるコマンドです。さてこの問題をこれまでどうしていたかというと、npmのrun-scriptというしくみを利用することが多かったのではないでしょうか。package.jsonのscriptsフィールドに実行したいコマンドを定義しておくことで、npm runで実行できるというものです。

$ grep -A 3 scripts package.json
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "cowsay": "cowsay"
  },

$ npm run cowsay -- 'マミ'

> project@1.0.0 cowsay /path/to/project
> cowsay "マミ"

 ______
< マミ >
 ------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

scriptsフィールドではローカルインストールしたパッケージのコマンドを直接実行できるテクニックを使用したものです。しかし"cowsay": "cowsay"のようなコマンドだけの定義が増えていくのはつらいものがありました。npxを使用することでこれらの問題から解放されます。

実践例

先述したように、scriptsフィールドにコマンドのみ定義していたようなケースは、ほぼ置き換えられるのではないでしょうか。オプションや引数も込みで定義しているものは、無理に置き換える必要はありません。

$ npx mocha
$ npx gulp
$ npx textlint
$ npx eslint
$ npx tsc

グローバルインストールせずに一度だけコマンドを実行する

簡潔に

事前にパッケージをインストールすることなく次のようにコマンドを実行できます。

$ which cowsay

$ npx cowsay 杏子
npx: 10個のパッケージを4.373秒でインストールしました。
 ______
< 杏子 >
 ------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

詳しく

npxコマンドをたたくと次の順番でコマンドを探します。

  1. ローカルパッケージ(node_modules/.bin
  2. 環境変数PATH
  3. npmレジストリ

大事なのは3で、たとえインストールされていないコマンドであっても、自動的にnpmレジストリからパッケージを探してくれます。見つけたパッケージは環境を汚さない場所にダウンロードされます *1。そのため先述した例のように、環境にコマンドが見つからなかった場合、npmレジストリから探してダウンロードし実行してくれるというわけです。このとき少し注意が必要で、npmレジストリから探すのは 指定したコマンドと同名のパッケージ です。そのため、パッケージ名とコマンドが異なる場合は-pオプションでパッケージ名を明示する必要があります。最近は@で始まるスコープを使用したパッケージ(Scoped packages)も増えていますので注意しましょう。

2は少しおもしろくて、環境変数PATHからコマンドを探すため、Nodeに関係ないコマンドもnpx経由で実行できます。

$ npx python3 -V
Python 3.7.0

実践例

プロジェクトのひな型を作成するユーティリティコマンドは数多く開発されています。npxがないと、それを一度グローバルインストールしてから、コマンドをたたいて作成という流れが普通でした。これらの準備が少し楽になりそうです。いくつか例を見てみましょう。

CDKプロジェクトの作成。cdkコマンドはディレクトリを作成してから実行する必要があるため、次のように実行できます。

$ mkdir example-cdk && cd $_ && npx cdk init app --language=typescript

Angularプロジェクトの作成。ngコマンドは@angular/cliパッケージで提供されています。

$ npx -p @angular/cli ng new example-angular

Reactプロジェクトの作成。このコマンドはReact公式のチュートリアルでも紹介されています。

$ npx create-react-app example-react

Vueプロジェクトの作成。Vue CLIで作成したプロジェクトは、@vue/cliがローカルインストールされていないため、追加でインストールしておくのがお勧めです。

$ npx -p @vue/cli vue create example-vue
$ cd $_ && npm install -D @vue/cli

claspプロジェクトの作成。claspコマンドは必要最低限のファイルしか作成しないため、少しやることが多いです。

$ mkdir example-clasp && cd $_ && npm init -y && npm install -D @google/clasp
$ npx clasp login
$ npx clasp create --type sheets --rootDir src --title 'GAS Example'

指定したバージョンのNodeで実行する。私は普段nvmを使用していますが、ワンショットで別のバージョンを試したい場合などに便利そうです。

# コマンドにバージョンを指定する
$ npx node@12 -v
v12.8.1

# モジュールバージョンを指定し、その環境でnpmコマンドを実行
$ npx -p node@12 npm rebuild node-sass

GitHubやGistで公開されているスクリプトを実行する

簡潔に

GitHubやGistで公開されているスクリプトを次のように実行できます。

$ npx https://gist.github.com/1cd52daf43b11e9d2c72aa6ab0be59a3
npx: 1個のパッケージを6.613秒でインストールしました。
yay gist

詳しく

npx登場以前から、npmリポジトリに登録されていないパッケージをnpmコマンドでインストールすることは可能でした。

$ npm install https://gist.github.com/1cd52daf43b11e9d2c72aa6ab0be59a3

とはいえ、「ちょっと試したい/試してもらいたい」という用途には使いづらさがありました。試したらアンインストールしないとゴミとして残ってしまいます。npxで直接実行できるようになったことで、より手軽さが増したのではないでしょうか。

実践例

ちょっとした処理の自動化などに活用できそうです。たとえばclaspプロジェクトの作成例を先ほど紹介しましたが、実際の開発では追加のパッケージインストールや、Git管理する場合はgit initなども必要になります。これらの処理をあらかじめスクリプトで書いておくと、以降はそれを実行するだけで定型処理を自動化できます。

$ npx https://gist.github.com/74c68c24a440c7cfbd78ccce5e9652d4 example-clasp
$ cd $_
$ npx clasp login
$ npx clasp create --type sheets --rootDir src --title 'GAS Example'

create clasp app project.はディレクトリの作成、Gitリポジトリ初期化、npmパッケージインストールといった処理をするスクリプトです。エラーハンドリングなど手抜いていますが、まずはあまり作り込まずに使い始めてみてはいかがでしょうか。

まとめ

いつの間にかnpmに同梱されていたnpxコマンド。調べてみたらとても便利なコマンドでした。もしまだ使ったことのない方がいれば、ぜひ試してみてください。私はがっつり使っていきます!

参考URL

脚注

  1. 私の環境では ~/.npm/_npx/${process_id} にダウンロードされています