Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
🛵

zxを使ってみた

2021/12/17に公開

zx とは

zxはNodeのchild_processのラッパーで、JavaScriptで記述したスクリプトをNodeで実行し、
shellコマンドを発行できます。
一言で表すと、お手軽にJavaScriptで記述し、実行できるshellです。
googleから公開され、2021年初頭に話題になりました。(google/zx: https://github.com/google/zx)
筆者は普段からスクリプトはbashで実行している一方、業務で使い慣れているTypeScriptの型をzxで使えるとマニュアルで見かけ、使ってみました。

zx の導入

zxを利用するには、まず、Nodeのバージョンが14.13.1以上である必要があります。
Nodeの準備が整っていれば、以下でインストールします。

npm i -g zx

zxで実行するスクリプトは、top-level-awaitを利用すべく、.mjs拡張子での作成が推奨されています。
.jsで作成する場合、コマンドの発行部分でvoid async function(){...}()と記述する必要があり、少し長くなってしまいます。

zx の使用

以下でいくつかzxの使用方法を解説します。

コマンドの発行

zxで利用するスクリプトでは、先頭に#!/usr/bin/env zxを記載し、それ以下へ処理を記述していきます。
また、以下のcommandの部分へ、shellで発行したいコマンドを記述します。

$`command`

以下はhello worldするスクリプトです。
変数の記述はJavaScriptで見慣れた記法そのものです。

#!/usr/bin/env zx
const word = "hello world";
await $`echo ${word}`;

作成したスクリプトは、以下のように実行します。

zx ./hello.mjs
$ echo $'hello world'
hello world

zx ./hello.mjsで実行した結果、$ echo $'hello world' とコマンドが出力された後、hello worldがechoされていることが分かります。コマンドおよび実行結果をコンソールへ出力させない場合、
zx ./hello.mjs --quietと実行することで、表示させないことができます。

関数/パッケージの利用

追加でインストールせずとも利用できる関数/パッケージについて一部紹介します。

  • sleep
    JavaScriptでのsetTimeoutをラップした関数です。以下ではneruをechoし、1秒待った後okitaがechoされます
#!/usr/bin/env zx
$`echo neru`;
await sleep(1000);
$`echo okita`;
zx ./wakeup.mjs
$ echo neru
neru
$ echo okita
okita
  • fetch
    zxではnode-fetchをラップしたfetch関数を以下のように利用できます。
#!/usr/bin/env zx
const resp = await fetch("https://www.forcia.com/");
console.log(resp.ok);
zx ./fetchForcia.mjs
$ fetch https://www.forcia.com/
true

TypeScript で書いてみる

筆者は業務において、JavaScriptを生で記述する機会はほとんどなく、TypeScriptを使用しています。
zxのマニュアルにも記載がありますが、zxのスクリプトをTypeScriptで記述し、実行してみます。

まず、実行するにはts-node,typescriptが必要なので、インストールします。
npm i -g ts-node
npm i -g typescript

hello worldするスクリプトは以下のように記述できます。

#!/usr/bin/env zx
import "zx/globals";

const word: string = "hello world";

void (async function () {
    await $`echo ${word}`;
})();

ここでは以下で実行します。

ts-node tsZx.ts
$ echo $'hello world'
hello world

TypeScriptでの記述なので以下のような不正な記述に対し、警告を発報してくれます。
もちろんts-nodeで実行してみても同じ型エラーが発報され実行はされません。
type_anger

また、TypeScriptをVScodeで記述する際によく活用される、 "F12を押して関数へジャンプ"がここでも可能です。
以下画像はzxでの$関数へジャンプしている画像です。
jump

さらに、以下のように別途index.d.tsを用意します。

interface Hello {
    word: string;
    language: string;
}
export type HelloWords = Hello[];

それをzxで実行するスクリプトへimportして型を利用できます。

#!/usr/bin/env zx
import "zx/globals";
import { HelloWords } from ".";

const words: HelloWords = [
    {
        word: "こんにちは",
        language: "Japanese",
    },
    {
        word: "Hello",
        language: "English",
    }
];

Promise.all(
    words.map(w => {
        $`echo word: ${w.word} language: ${w.language}`;
    })
);

ts-node tsZxType.ts
$ echo word: $'こんにちは' language: Japanese
$ echo word: Hello language: English
word: こんにちは language: Japanese
word: Hello language: English

筆者はShellよりもTypeScriptでの記述の方が親しみがあるためか、
zxでの記述が見通しがいいように感じられます。

使ってみた感想

慣れた方は普通にShellで書いた方が早そうではありますが、JavaScriptに親しみがある方は使用してみてもいいかもしれません。
TypsScriptの実行環境を整える手間はありますが、TypeScriptの便利さをShellでも再現できたのには感動しました。

この記事を書いた人

田中柾伎
2020年1月キャリア入社エンジニア
最近、ターンテーブル2台で曲を繋ぐ練習をしています。

FORCIA Tech Blog

Discussion