Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotreload: Ability to update templates without recompiling #451

Open
wants to merge 45 commits into
base: main
Choose a base branch
from

Conversation

untitaker
Copy link

@untitaker untitaker commented Nov 17, 2024

This is a continuation of #392, it adds a way to auto-reload templates to maud without going through rustc at all, for some situations.

Basic usage

Enable the hotreload feature, and the html! macro will partially evaluate at runtime. use maud::html_static! to force the "normal", fully-compiled behavior.

You can use export MAUD_ON_ERROR=exit to make maud call std::process::exit during template-rendering whenever it turns out the code changes are too severe for hot-reloading. In combination with cargo watch, this can hot-reload your web app's templates when possible, and recompile when that fails:

MAUD_ON_ERROR=exit  cargo watch --no-restart -x run --features hotreload

This has some limitations because now rust code changes unrelated to templates will not cause the application to restart. Needs further improvements.

Internals

maud+hotreload will compile your template into two parts:

  1. a list of "formatting arguments" where all the rust code in templates is eagerly evaluated
  2. a runtime that opens the sourcecode found via file!(), tries to parse out the original macro invocation, and attempts to use the existing "formatting arguments" with that

This means that changes such as this can be hot-reloaded:

// before
html! {
    "Hello " (world) "!"
}

// after (no recompilation needed, as only static content changed)
html! {
    "Goodbye " (world) "!"
}

but this change requires proper recompilation:

// before
html! {
    "Hello " (world) "!"
}

// after (recompilation needed, as rust code changed)
html! {
    "Hello " (other_world) "!"
}

the compiled code is very inefficient, as it re-parses rust sourcecode at runtime (still faster than rustc). there are some complications, such as the hot-reloading:

  • not working in doctests
  • not working whenever the html! macro is aliased or used from within another macro
  • not working when html! { } is written in a weird way, such as html! /* { */ {

Is this really for maud?

Even though there are no added dependencies, the feature is still a lot to maintain and required a lot of restructuring. I think most of the restructuring was unavoidable, and now there are three crates instead of two.

I don't necessarily have expectations that this will be merged, but on the other hand I also really want a template engine that is type-safe, has fast iteration-speeds and can be composed in a JSX-like way using regular Rust functions. I think maud+hotreload is the only standalone templating engine in the Rust ecosystem that can do that right now. So I'd be willing to fork maud and continue development there if people are interested. It seems there are a few other PRs that need attention anyway.

finally, thanks to @wrapperup for the initial prototype and architecture of hot-reloading.

@jrey8343
Copy link

This is exactly the feature I’m looking for!
Following 🍿🍿

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants