🌶️

Rust | cargo-watch でコードの変更を検知 & ホットリロード

2023/09/30に公開
2

Rust でホットリロードしたい

npm でいうところの npm-watch のように、
コードの変更を自動検知してホットリロードさせていきたいと思います。

Web アプリケーションの開発など、修正して cargo run を繰り返すのは億劫な作業です...

ホットリロードで快適な開発環境を実現しましょう🚀

axum で Web アプリケーションを作成

Web アプリケーションの開発での利用を想定して、
今回は axum で簡単なデモアプリケーションを用意していきます。

example-app

まずはプロジェクトを作成します。

cargo new example-app

次に必要なクレートを追加します。

cargo add axum
cargo add tokio --features full

最後に main.rs を書き換えます。

main.rs
use std::net::SocketAddr;
use axum::{response::Html, routing::get, Router};

#[tokio::main]
async fn main() {
    // build our application with a route
    let app = Router::new().route("/", get(handler));

    // run it
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    println!("listening on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn handler() -> Html<&'static str> {
    Html("<h1>Hello, World!</h1>")
}

公式の examples がエラー ?!

公式 examples の hello-world がそのままでは動きませんでした🫥🫥

上記 main.rs では、以下のような修正を加えています。

main.rs
use axum::{response::Html, routing::get, Router};

#[tokio::main]
async fn main() {
    // build our application with a route
    let app = Router::new().route("/", get(handler));

    // run it
-   let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
-       .await
-       .unwrap();
-   println!("listening on {}", listener.local_addr().unwrap());
-   axum::serve(listener, app).await.unwrap();
+   let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
+   println!("listening on {}", addr);
+   axum::Server::bind(&addr)
+       .serve(app.into_make_service())
+       .await
+       .unwrap();
}

async fn handler() -> Html<&'static str> {
    Html("<h1>Hello, World!</h1>")
}

cargo-watch

Web アプリケーションを用意できたので、cargo-watch を試していきます🙌

https://github.com/watchexec/cargo-watch

インストール

cargo-watch は cargo でインストールする必要があります。

cargo install cargo-watch

cargo watch

cargo-watch のデフォルトの実行コマンドは cargo check です。

cargo watch
% cargo watch             
[Running 'cargo check']
    Checking cargo-watch-example v0.1.0 (/example-app)
    Finished dev [unoptimized + debuginfo] target(s) in 0.52s
[Finished running. Exit status: 0]
[Running 'cargo check']
    Checking cargo-watch-example v0.1.0 (/example-app)
    Finished dev [unoptimized + debuginfo] target(s) in 0.24s
[Finished running. Exit status: 0]

cargo check はバイナリを生成せずにプロジェクトをビルドして、エラーがないか確認できることができます。

バイナリの生成をスキップするので、cargo build などに比べて高速に動作します。

cargo wathc -x run

cargo run を実行したい場合、-x, --exec オプションでコマンドを指定します。

cargo watch -x run
% cargo watch -x run       
[Running 'cargo run']
   Compiling cargo-watch-example v0.1.0 (/example-app)
    Finished dev [unoptimized + debuginfo] target(s) in 0.94s
     Running `target/debug/cargo-watch-example`
listening on 127.0.0.1:3000
[Running 'cargo run']
   Compiling cargo-watch-example v0.1.0 (/example-app)
    Finished dev [unoptimized + debuginfo] target(s) in 0.72s
     Running `target/debug/cargo-watch-example`
listening on 127.0.0.1:3000

コードを変更すれば、すぐに cargo run が実行されます。

これで、開発効率アップ!!

生産性アップも間違いなしです🎉🎉

ディレイの時間を指定する

-d, --delay オプションを指定することで、
検知からコマンド実行まで時間(秒)を変更することができます。

なお、デフォルトは 0.5 秒です。

cargo watch -x run -d 5

まとめ

cargo-watch の導入と実行手順のご紹介でした。
インストールするだけで、すぐに使用できますし、導入しない理由はないですね✨

便利なツールを開発してくださるエンジニアには感謝です。

参考

脚注
  1. 🚨 The main branch has unpublished, breaking changes 🚨 ↩︎

コラボスタイル Developers

Discussion

bouzuyabouzuya

axum の README に記載の通り、 main ブランチは現在 0.7 向けのコードになっているため crate.io に公開されている 0.6.x では動かなくなっており、必要なら v0.6.x のブランチを参照すると良いです。
https://github.com/tokio-rs/axum#-the-main-branch-has-unpublished-breaking-changes-

山とコード山とコード

ご指摘いただきありがとうございます!
追記する形で訂正させていただきました。