zxを使ってみた
これは、FORCIA Advent Calendar 2021の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で実行してみても同じ型エラーが発報され実行はされません。
また、TypeScriptをVScodeで記述する際によく活用される、 "F12を押して関数へジャンプ"がここでも可能です。 以下画像はzxでの$
関数へジャンプしている画像です。
さらに、以下のように別途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台で曲を繋ぐ練習をしています。
フォルシアではフォルシアに興味をお持ちいただけた方に、社員との面談のご案内をしています。
採用応募の方、まずはカジュアルにお話をしてみたいという方は、お気軽に下記よりご連絡ください。
※ 弊社社員に対する営業行為などはお断りしております。ご希望に沿えない場合がございますので予めご了承ください。