marc2332 / freya

Cross-platform GUI library for 🦀 Rust powered by 🧬 Dioxus and 🎨 Skia.
https://freyaui.dev/
MIT License
1.28k stars 51 forks source link

issue: Unexpected behaviors when editing dynamic parts with `hot-reload` #766

Open jsprog opened 1 week ago

jsprog commented 1 week ago

Let's consider the sample code below (counter)

to crash the app:

to freeze hot-reload:

development environment:

// main.rs

use freya::prelude::*;
use freya::hotreload::FreyaCtx;

fn main() {
    dioxus_hot_reload::hot_reload_init!(Config::<FreyaCtx>::default());
    launch(app)
}

#[component]
fn app() -> Element {
    let mut count = use_signal(|| 0);
    rsx!(
        rect {
            height: "50%",
            width: "100%",
            main_align: "center",
            cross_align: "center",
            background: "rgb(0, 119, 182)",
            color: "white",
            shadow: "0 4 20 5 rgb(0, 0, 0, 80)",
            label {
                font_size: "75",
                font_weight: "bold",
                "{count}"
            }
        }
        rect {
            height: "50%",
            width: "100%",
            main_align: "center",
            cross_align: "center",
            direction: "horizontal",
            Button {
                onclick: move |_| count += 1,
                label { "Increase" }
            }
            Button {
                onclick: move |_| count -= 1,
                label { "Decrease" }
            }
        }

    )
}
# Cargo.toml

[package]
name = "freya-intro"
version = "0.1.0"
edition = "2021"

[dependencies]
dioxus = { version = "0.5.1", default-features = false, features = ["hooks", "macro"] }
dioxus-hot-reload = "0.5.0"
dioxus-router = "0.5.0"
freya = { git="https://github.com/marc2332/freya", features = ["hot-reload"]}
# freya = { version = "0.2.2", features = ["hot-reload"] } # note: this even failed with hot-reload
jsprog commented 1 week ago

For the second case (to freeze hot-reload), I'm receiving this terminal message:

Rebuild needed... shutting down hot reloading.
Manually rebuild the application to view further changes.

how can I automate rebuild when requested by freya?

marc2332 commented 1 week ago

Hey,

Support for Dioxus hotreload is limited, can only edit static parts, this means that changing "{count}" or any other dynamic code will lead to unexpected behaviors. You will even get the Rebuild needed... shutting down hot reloading. message as you shared, that is when Dioxus can't simply figure out how to hotreload the code.

And no, Freya cannot request another build because it's being run through by cargo whereas Dioxus has a custom CLI, something I am not willing to do as I prefer to just use cargo.

That said, I might actually just remove hot reload in the next release. I don't think most people use it (I don't at least) because of how not-worth using it is. Maybe once Dioxus gets decent support for binary patching, I could support it in Freya

jsprog commented 1 week ago

That said, I might actually just remove hot reload in the next release

hot-reload existed to increase productivity when coding apps, and despite the limits mentioned above, it helps saving developer's time when styling and positioning content.

And no, Freya cannot request another build because it's being run through by cargo

Maybe once Dioxus gets decent support for ....

Currently, the logs are available to recommend a manual restart, and by invoking cargo run as a child process, we should be able to decide when to kill and re-spawn again as cargo watch -x 'cargo run' is doing!

node run.js

// run.js
const { spawn } = require('child_process');

spawn_cargo()

function spawn_cargo() {
    const child = spawn('cargo', ['run']);

    child.stdout.on('data', (data) => {
        console.log(`${data}`)
        if (data.indexOf("Manually rebuild the application to view further changes.") > -1) {
            child.kill('SIGINT')
            spawn_cargo()
        }
    });

    child.stderr.on('data', (data) => {
        console.error(`${data}`)
    });

    child.on('error', (error) => {
        console.error(`error: ${error.message}`);
    });

    child.on('close', (code) => {
        console.log(`child process exited with code ${code}`);
    });
}
marc2332 commented 1 week ago

Currently, the logs are available to recommend a manual restart, and by invoking cargo run as a child process, we should be able to decide when to kill and re-spawn again as cargo watch -x 'cargo run' is doing!

node run.js

// run.js
const { spawn } = require('child_process');

spawn_cargo()

function spawn_cargo() {
    const child = spawn('cargo', ['run']);

    child.stdout.on('data', (data) => {
        console.log(`${data}`)
        if (data.indexOf("Manually rebuild the application to view further changes.") > -1) {
            child.kill('SIGINT')
            spawn_cargo()
        }
    });

    child.stderr.on('data', (data) => {
        console.error(`${data}`)
    });

    child.on('error', (error) => {
        console.error(`error: ${error.message}`);
    });

    child.on('close', (code) => {
        console.log(`child process exited with code ${code}`);
    });
}

Yeah sure but that would require a small CLI as you can see, if you want to make a rust POC maybe I could consider it.