dioxus/packages/hot-reload
Evan Almloff 34bdcd15cf
Switch to a pool of dynamic values for hot reloading (#2705)
* create the dynamic value pool

* assign ids to dynamic formatted segments

* separate the rendering and literal pools

* rsx output compiles again

* more examples compiling with new rsx expansion

* update template body explanation

* all workspace examples compile

* fix formatted segments in keys

* start hot reload diffing

* fix component literal hot reloading

* start integrate new hot reloading with the CLI

* simple hot reloads working

* Fix hot reloading blocks with components

* implement hot reloading for if chains

* Fix hot reloading after a template requires a full rebuild

* Fix hot reloading any attribute values

* remove unsafe from hot reload utils

* Fix hot reloading empty rsx

* add more hot reloading tests

* reorganize hot reload module

* fix web hydration

* fix empty rsx nodes in autoformatting

* fix tests

* remove path sorting logic from core

* make template names more consistent in debug mode

* fix quote_as_hot_reload_literal for explicitly typed literals

* fix can_be_shorthand for string literals

* fix formatted single dynamic expression

* Fix usize component properties and playwright tests

* remove default implementation for TemplateBody

* add a bunch more comments for diffing, scoring and why this scoring system is optimal
2024-07-30 17:16:27 +00:00
..
src Switch to a pool of dynamic values for hot reloading (#2705) 2024-07-30 17:16:27 +00:00
Cargo.toml Hotreloading of for/if/body, formatted strings, literals, component props, nested rsx, light CLI rewrite, cli TUI (#2258) 2024-07-17 19:11:18 -07:00
README.md fix most typos, add crate-ci/typos to CI (#2653) 2024-07-23 17:49:33 -07:00

dioxus-hot-reload: Hot Reloading Utilities for Dioxus

Crates.io MIT licensed Build Status Discord chat

Website | Guides | API Docs | Chat

Overview

Dioxus supports hot reloading for static parts of rsx macros. This enables changing the styling of your application without recompiling the rust code. This is useful for rapid iteration on the styling of your application.

Hot reloading could update the following change without recompiling:

rsx! {
    div {
        "Count: {count}",
    }
}

=>

rsx! {
    div {
        color: "red",
        font_size: "2em",
        "Count: {count}",
    }
}

But it could not update the following change:

rsx! {
    div {
        "Count: {count}",
    }
}

=>

rsx! {
    div {
        "Count: {count*2}",
        onclick: |_| println!("clicked"),
    }
}

Usage

This crate implements hot reloading for native compilation targets not WASM. For hot reloading with the web renderer, see the dioxus-cli project.

Add this to the top of your main function on any renderer that supports hot reloading to start the hot reloading server:

fn main(){
    hot_reload_init!();
    // launch your application
}

By default the dev server watches on the root of the crate the macro is called in and ignores changes in the /target directory and any directories set in the .gitignore file in the root directory. To watch on custom paths pass call the with_paths function on the config builder:

fn main(){
    hot_reload_init!(Config::new().with_paths(&["src", "examples", "assets"]));
    // launch your application
}

By default the hot reloading server will output some logs in the console, to disable these logs call the with_logging function on the config builder:

fn main(){
    hot_reload_init!(Config::new().with_logging(false));
    // launch your application
}

To rebuild the application when the logic changes, you can use the with_rebuild_command function on the config builder. This command will be called when hot reloading fails to quickly update the rsx:

fn main(){
    hot_reload_init!(Config::new().with_rebuild_command("cargo run"));
    // launch your application
}

If you are using a namespace other than html, you can implement the HotReloadingContext trait to provide a mapping between the rust names of your elements/attributes and the resulting strings.

You can then provide the Context to the builder to make hot reloading work with your custom namespace:

fn main(){
    // Note: Use default instead of new if you are using a custom namespace
    hot_reload_init!(Config::<MyContext>::default());
    // launch your application
}

Implementing Hot Reloading for a Custom Renderer

To add hot reloading support to your custom renderer you can use the connect function. This will connect to the dev server you just need to provide a way to transfer Templates to the VirtualDom. Once you implement this your users can use the hot_reload_init function just like any other render.

async fn launch(app: Component) {
    let mut vdom = VirtualDom::new(app);
    // ...

    let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
    dioxus_hot_reload::connect(move |msg| {
        let _ = tx.send(msg);
    });

    loop {
        tokio::select! {
            Some(msg) = rx.recv() => {
                match msg{
                    HotReloadMsg::Shutdown => {
                        // ... shutdown the application
                    }
                    HotReloadMsg::UpdateTemplate(template) => {
                        // update the template in the virtual dom
                        vdom.replace_template(template);
                    }
                }
            }
            _ = vdom.wait_for_work() => {
                // ...
            }
        }
        let mutations = vdom.render_immediate();
        // apply the mutations to the dom
    }
}

Contributing

  • Report issues on our issue tracker.
  • Join the discord and ask questions!

License

This project is licensed under the MIT license.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Dioxus by you shall be licensed as MIT without any additional terms or conditions.