Home
| Colors: |

Watch A Directory For File Changes While Hot Reloading Web Pages

September 2023

This is the process I'm using for Neopoligin to rebuild and reload the site when source files change.

use axum::Router;
use notify::RecursiveMode;
use notify::Watcher;
use notify_debouncer_mini::new_debouncer;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::time::Duration;
use tower_http::services::ServeDir;
use tower_livereload::LiveReloadLayer;

#[tokio::main]
async fn main() {
    tokio::spawn(async {
        let _ = watch_files();
    });
    let _ = run_web_server().await;
}

async fn run_web_server() -> std::result::Result<(), Box<dyn std::error::Error>> {
    let livereload = LiveReloadLayer::new();
    let reloader = livereload.reloader();
    let app = Router::new()
        .nest_service("/", ServeDir::new(Path::new("html")))
        .layer(livereload);
    let mut watcher = notify::recommended_watcher(move |_| reloader.reload())?;
    watcher.watch(Path::new("html"), notify::RecursiveMode::Recursive)?;
    axum::Server::bind(&"0.0.0.0:3030".parse()?)
        .serve(app.into_make_service())
        .await?;
    Ok(())
}

fn watch_files() -> notify::Result<()> {
    let watch_dir = PathBuf::from("/some/source/dir");
    let output_file =
        PathBuf::from("/some/output/file.html");
    let (tx, rx) = std::sync::mpsc::channel();
    let mut debouncer = new_debouncer(Duration::from_millis(100), tx)?;
    debouncer
        .watcher()
        .watch(&watch_dir, RecursiveMode::Recursive)?;
    for result in rx {
        match result {
            Ok(events) => events.iter().for_each(|event| {
                // BUILD FROM SOURCE FILE HERE
                let _ = fs::write(
                  output_file.clone(), 
                  format!("{}", &event.path.display())
                );
            }),
            Err(_) => {}
        }
    }
    Ok(())
}

Installs

cargo add axum
cargo add tokio --features "rt-multi-thread,macros"
cargo add tower-http --features "fs"
cargo add tower-livereload
cargo add notify
cargo add notify_debouncer_mini

TODO

    Write up notes on how this works

end of line