leptos-rs / leptos

Build fast web applications with Rust.
https://leptos.dev
MIT License
16.28k stars 648 forks source link

[hot reload] Hot reload broken for children after components #3191

Open omani opened 1 day ago

omani commented 1 day ago

Describe the bug To reproduce clone this repo, which is a fresh starter axum-0.7 template with additionally tailwind included. https://github.com/omani/lep7

as mentioned in discussion #2919: hey @gbj. has something changed recently? I again started with the axum-0.7 template and hot-reloading works, but totally wrong children are being replaced in my browser. Im adding a <p> for example, and a weird button is added to the DOM. also removing children does not work properly. this is a very weird behavour I hadnt seen 2 months ago (back then when I had set up the axum template with tailwind, etc.).

there is a button below the <p>. I remove the <p> and the button is removed in the DOM (all of this while using --hot-reload ofc). very strange.

tested with firefox and chromium.

this video shows the weird behavour: https://github.com/user-attachments/assets/cb71fe4c-bba6-478e-816a-9f25cf58d851

https://github.com/user-attachments/assets/cb71fe4c-bba6-478e-816a-9f25cf58d851

Leptos Dependencies

Please copy and paste the Leptos dependencies and features from your Cargo.toml.

For example:

axum = { version = "0.7", optional = true }
console_error_panic_hook = "0.1"
leptos = { version = "0.7.0-rc0", features = ["nightly"] }
leptos_axum = { version = "0.7.0-rc0", optional = true }
leptos_meta = { version = "0.7.0-rc0" }
leptos_router = { version = "0.7.0-rc0", features = ["nightly"] }
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
wasm-bindgen = "=0.2.93"
thiserror = "1"
tracing = { version = "0.1", optional = true }
http = "1"

To Reproduce Steps to reproduce the behavior:

  1. Clone the repo
  2. execute cargo leptos watch --hot-reload
  3. change something in the App component's view (add a `

    ' or something else)

Expected behavior I expect it to insert/update the correct child/children when changing something in the HTML view

Screenshots see link to discussion video above

Additional context this wasn't the case 3 months ago. this is new to me.

gbj commented 1 day ago

Thanks. This is much better than the version in the discussion, because 1) it includes the app you're using and 2) it has a specific "do this and this breaks."

Specifically, the issue here seems to be "Hot reloading doesn't work after components that return ()". In this case, those are the meta components in the App. This makes sense to me intuitively -- hot-reloading works by saying things like "Hey, modify the 4th child" or "Move the 4th child to be 5th instead". Components like this used to have a DOM representation, but no longer do — which is good, but messes with hot-reloading!

Playing around with your example I notice also that it doesn't work with raw text nodes (as opposed to quoted string nodes). Like I said I haven't really touched any of the hot reloading code in about a year and a half... it's possible we didn't even support unquoted text nodes when I wrote it.

Thanks for the example, will list this as a nice-to-have thing to fix in 0.7 but not a blocker for releasing that.

omani commented 1 day ago

so is there something I can do until this is fixed? Im asking because it is a huge disadvantage not having this hot-readling feature since it is a nice DX. especially when you are on a slow machine and compiling the WASM is very slow (like in my case).

gbj commented 1 day ago

Here are some options: 1) Help fix it — It's an open-source project, not a commercial product. 2) Pull some part of the view out into a separate view macro. Hot-reloading works on a per-view basis, so if the problem is "Hot reloading is broken after components XYZ," then pulling some content out separately and editing it can work.

For example, to test out this hypothesis I opened up your app, and started editing a separate let content = view! { /* ... that I added to the App. Like I said, the issue is not that hot-reload doesn't work, it's that there are a handful of edge cases it doesn't work on.

https://github.com/user-attachments/assets/81955500-06b2-4dd6-884c-481ac0b40e5a