💎

【Go】ホットリロードツールの枠に収まらないReflexのススメ

2021/09/12に公開

皆さんはGoでサーバーを立てるときどんなホットリロードツールを使っていますか?
airもめちゃくちゃ良いですよね。

でも僕はここであえてReflexを推していきたいと思います。

Reflexとは?

https://github.com/cespare/reflex
Go製のホットリロードツールです。
ファイルの作成・変更を検知してコマンドを実行してくれます。

reflex -r '(\.go$|go\.mod)' -s go run main.go

そして、この一行だけで.goファイルとgo.modファイルの作成・変更を検知してくれます。
ぅゎ、っょぃ

以下ではgithubに書いている仕様のおさらいと、こんなことにも使えるんでねーの?というところについて、そして最後にはオプションについて書いていこうと思います。

Reflexの特徴

Reflexは基本的に
reflexコマンド + reflexのオプション + セパレーター(--) + 実行コマンド からなります。
例を挙げてみると

reflex -r '\.go$' -- cat -n {}

こんな感じのコマンドを使って例えば下記のコードのように変更を加えると

response.go
package domain

type Response struct {
	Code   int32       `json:"code,omitempty"`
	Object interface{} `json:"object,omitempty"`
	Err    error       `json:"err,omitempty"`
	Text   string      `json:"text,omitempty"`
}
結果
[00]  1     package domain
[00] 2     
[00] 3     type Response struct {
[00] 4             Code   int32       `json:"code,omitempty"`
[00] 5             Object interface{} `json:"object,omitempty"`
[00] 6             Err    error       `json:"err,omitempty"`
[00] 7             Text   string      `json:"text,omitempty"`
[00] 8     }

cat -n 変更したファイルの結果が出力されました!

って、--とか{}とかなんやねん!!!!!! 
となると思うので以下で説明します。

-- セパレータについて

まずはこちらのセパレータについてですが、reflexの構文は

  • reflex部分
  • reflexオプション
  • (--)セパレータ
  • 実行コマンド

からなると言いましたが、つまりreflexのオプションbashコマンドのオプションが一行のコマンドに共存しなければならないということです。

これらの棲み分けをするためにセパレータ(--)を使います。

なので実行コマンドでオプションを使いたい時にreflex自体のオプションだと思われないように使うものだと思ってもらえれば大丈夫です。👍

{} Substitutionについて

次にこの{}ですが、これは置換記法です。
つまり、この{}は変更が検知されたファイル名が置き換えられます。

先程の例だと.go拡張子がつくファイルで変更が検知されたらcat -n {}が実行されるのですが、その際に{}部分を変更が検知されたファイル名に置き換えて実行されます。

reflex -r '\.go$' -- cat -n {}

ちなみに{}記号をどうしても使いたくない時は--substitute="" オプションを使うことで変更できます。

例) {}を@@にしたい!  -> reflex -r '\.go$' --substitute="@@" -- cat -n @@

設定ファイルについて

さてさて、こんな感じに柔軟に書けそうなreflexコマンドですがゴリゴリ書いていくと長くなっちゃいそうな感じがしますよね。

そんな時に設定ファイルに書き出すことができます!

下記のようにreflex.confを作ります。
中身はreflexコマンドからreflexの文字を除いたものです。(簡単❗️)

reflex.conf
# コメントもかけちゃうよ!
-r '\.go$' -- cat -n {}

ちなみにこのファイルを実行するときは下記のように-cオプションをつけてファイルを指定すると実行できます!

reflex -c reflex.conf

基本的な部分についてはこんな感じです!

応用例

①監視対象によってコマンドを使い分ける

今回は.ymlの変更を検知した時と、.goの変更を検知した時別々の処理をしたい例です。
まず、hoge.confで設定ファイルを作成します。

hoge.conf
-r '\.go$' -- cat -n {}

-r '(\.yaml$|\.yml$)' echo "change yaml"

これを実行してそれぞれに変更を加えると

$ reflex -c hoge.conf
# ↓結果
[00] 1     package domain
[00] 2     
[00] 3     type Response struct {
[00] 4             Code   int32       `json:"code,omitempty"`
[00] 5             Object interface{} `json:"object,omitempty"`
[00] 6             Err    error       `json:"err,omitempty"`
[00] 7             Text   string      `json:"text,omitempty"`
[00] 8     }
[01] change yaml

.goを検知した時と.ymlを検知した時別の処置を行えます!

これの何がいいの?

これができるとエラーログが吐き出されるとS3にログを追加させたり、拡張子によってコンパイルを変えたりと割と多彩なことができます。

②コマンドをループさせる

$ reflex -r '\.log$' -- curl http://localhost:3000 >> response.log

とかをすると、response.logを監視しつつ、変更を検知するとcurlの結果をresponse.logに追記します。そうすると、またcurlが実行.........(以下略)
とループを起こせる?と思いやってみました!

上記コマンドを実行して、echo "start" > response.logをすると、、、
少し待ってcat response.logした結果がこちらです

$ cat response.log
start
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused
[00] (error exit: exit status 7)
[00] curl: (7) Failed to connect to localhost port 3000: Connection refused

で、出来とる!?localhostにサーバーを立てているわけではないのでエラーが出るのは正常です!
これは考えれば面白い使い方がまだまだできそう。。。

可能性を感じる、、、

Reflexオプションの紹介

最後にオプションをgithubのREADMEに沿って紹介します。githubにほとんど同じことが書いてあるので読み飛ばしても大丈夫です。

OPTIONS are given below:
  -c, --config="":
   .confファイルやコマンドラインから設定を読み取るオプション
       ex) reflex -c reflex.conf
  -d, --decoration="plain":
   fancy にするとコマンドラインアウトプットに色がついてみやすくなる
   noneにすると[00]接頭辞が表示されなくなる
      default: [plain]
  -g, --glob=[]:
   監視するファイルやディレクトリを'*.<拡張子>'などで指定する
  -G, --inverse-glob=[]:
   監視対象から外すファイルやディレクトリを'*.<拡張子>'などで指定する
  -R, --inverse-regex=[]:
   監視対象から外すファイルやディレクトリを正規表現などで指定する
  -r, --regex=[]:
   監視するファイルやディレクトリを正規表現などで指定する
  -e, --sequential=false:
   複数の監視対象がある時に実行コマンドを同時に行うか同期的に行うか
  -t, --shutdown-timeout=500ms:
   サーバーを止めるまでの待ち時間
  -s, --start-service=false:
   長時間起動するアプリかどうか サーバーなど
  --substitute="{}":
   置き換えに使う記号
  -v, --verbose=false:
   詳細表示

まとめ

Reflex使ってみたくなりましたか?
私自身書いてて、まだまだ面白いことができそうでさらに使ってみたくなりました!
設定ファイルの管理が俗人化してしまいそうですがちゃんと管理すればチーム開発でも大いに役立ってくれそうですね!

それではありがとうございました!

Discussion