Note: This site is currently "Under construction". I'm migrating to a new version of my site building software. Lots of things are in a state of disrepair as a result (for example, footnote links aren't working). It's all part of the process of building in public. Most things should still be readable though.

Watch A Directory For File Changes While Hot Reloading Web Pages

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

Code

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(())
}

Code

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
  • Write up notes on how this works