Googleさんの zx をローカルインストールして「nodeコマンドで実行」／「ファイルを直接指定して実行」

この記事の内容は、昨年末のアドベントカレンダー用の記事でも扱った、[Googleさんの zx](https://github.com/google/zx) に関するものです。

●【Backlog 2021】 Googleさんの zx で Backlog API を扱う（JavaScript で課題を追加する） - Qiita
　https://qiita.com/youtoy/items/36ea84e09332d4e6815a

## 何をやるか
今回の記事で扱う内容は、以下のとおりです。

- `npm i zx` で zx をローカルにインストールして使う
- `node ●●.mjs` というような nodeコマンドを使った処理の実行
- `./●●.mjs` というようなファイルを直接実行する形での処理

## 下準備
冒頭の記事でも書いている、今回のセットアップの話をざっくり書きます。
なお、自分が試している環境は Mac で、Node.js のバージョンは 14.18.2 です。

Node.js のバージョンについては、公式ページに以下の指定がありますので、その点だけご注意ください。
![バージョン指定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/6b8fd61c-bf13-2d43-1344-acb8ba8b4100.jpeg)

### zx をローカルインストール
まずは以下のコマンドを任意の場所で実行します。

```bash
$ npm i zx
```

これで、コマンドを実行したフォルダに node_modulesフォルダがや package.json などができると思います。

### テスト用のプログラムを用意して zx コマンドで実行する
次に、上記の手順で npmコマンドを実行したフォルダに、JavaScript のプログラムのファイルを作ります。
ファイル名は適当に test.mjs にしました。

拡張子を mjs にしているのは、zx の公式ページの以下にも書いてある「top-level await」をシンプルに使うためです。
![mjsを使う話.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/737fb479-750f-ed08-eeee-e4dd41dafb20.jpeg)
test.js という名前にした場合、上記のとおり全体を `async function` でラップしてやる必要が出てきます。

#### テスト用のプログラム
ここで、シンプルなプログラムを用意してみます（補足は、プログラムの内容と実行結果の後に書きます）。
以下の処理内容は「lsコマンド」・「1秒間のスリープ」・「[chalk](https://www.npmjs.com/package/chalk) を使った色付きの文字出力」を順番に実行するという適当なものにしました。

```javascript:test.mjs
await $`ls`
await sleep(1000);
console.log(chalk.blue("Hello world!"));
```

#### プログラムを zxコマンドで実行する

まずは、zxコマンドで実行します。
グローバルインストールではなくローカルインストールを行ったために、直接 zxコマンドが使えません。それに関する対処として npxコマンドを使い　zxコマンドを実行します。

```bash
$ npx zx test.mjs
```

実行結果は以下の通りで、想定どおりの結果になりました。
（1行目の右端のあたりが実行コマンドで、2行目移行が実行結果の出力です）
![テスト実行.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/36f94cf8-9514-375d-a8f0-01ee96928df2.jpeg)

#### プログラムの補足
1行目は、公式ドキュメントの以下に書いてある方法で lsコマンドを実行しています。書き方は「$\`【コマンド】\`」という形です。
![コマンド実行.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/5572bd9f-4b20-8ce2-8ce9-bece1faeb173.jpeg)

2行目は、公式ドキュメントの以下に書いてある関数を利用しています。
![スリープ関数.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/dd828102-710c-c0ff-31c5-243fdfb9da91.jpeg)
これは[公式ドキュメントの「Functions」という項目](https://github.com/google/zx#functions)で書かれた内容のうちの 1つです。
他にも、`cd()`、`fetch()`、`question()`、`nothrow()`などが、Functions という項目の部分に書かれています。

3行目は、公式ドキュメントの以下に書いてある関数を利用したものです。
![chalkパッケージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/0e5aa028-9d26-91d0-4f57-fd7c93fa858f.jpeg)
chalkパッケージをインポートすることなく利用できる状態にしているようです。

### テスト用のプログラムを少し書きかえて nodeコマンドで実行する
次に、上で用いていたプログラムを少し書きかえて、nodeコマンドで実行できるようにしてみます。
ちなみに、上記のプログラムをそのまま実行すると `$ is not defined` というエラーになります。

それを避けるために、以下に書かれた対応（`import 'zx/globals'`という行を冒頭に追加）をします。
![実行方法.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1aafef49-608f-80ed-65f7-2b60b6e9f314.jpeg)
その対応を行った後のプログラムは、以下のようになります。

```javascript:test.mjs
import 'zx/globals'

await $`ls`
await sleep(1000);
console.log(chalk.blue("Hello world!"));
```

再度、nodeコマンドで実行してみると、今度は無事に処理が完了しました。
![nodeコマンドで実行.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/88e96e03-1ff4-2c46-f0d2-f4df0fcca16a.jpeg)

### プログラムをまた少し書きかえてからファイルを直接指定する形で実行
今度は、ファイルを直接指定して実行できる形にして、プログラムを実行してみます。
この後のプログラムのファイル名は、上記と区別するために「test2.mjs」に変えました（前のままでも問題はないのですが...）。

ファイルを直接指定して実行できるようにするため、mjsファイルに実行権限を付与します。

```bash
chmod +x test2.mjs
```

この後、 `./test2.mjs` という形で、ファイルを直接指定して実行することができますが、今は実行後にエラーが発生します。
そこで、以下の記事などにも書かれている「[shebang（hashbang）](https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%90%E3%83%B3_(Unix))」を、プログラムの冒頭に追加します。

●JavaScriptと #!
　https://zenn.dev/qnighy/articles/d2712de8e4585f749b30

これで、test2.mjs を何を使って実行するか（つまり、nodeコマンドで実行すること）を指定できます。

```javascript:test2.mjs
#!/usr/bin/env node
import 'zx/globals'

await $`ls`
await sleep(1000);
console.log(chalk.blue("Hello world!"));
```

再度、ファイルを直接指定して実行してみると、無事に動作させることができました。
![ファイルを直接指定して実行.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/9a20d6a5-4add-2960-a177-ab40247a05b5.jpeg)

## グローバルインストールして使う場合の話
今回の記事では、zx をローカルインストールして利用しました。
グローバルインストールをして使う場合は、公式ページや以下のページなどをご参照ください。

●Google発のJavaScriptで書けるシェル 「zx」 | DevelopersIO
　https://dev.classmethod.jp/articles/shell-zx/

●zxを使ってみた│FORCIA CUBE│フォルシア株式会社
　https://www.forcia.com/blog/002378.html