lustre-labs / lustre

An Elm-inspired framework for building HTML templates, single page applications, and server-rendered components in Gleam!
https://hexdocs.pm/lustre
MIT License
727 stars 52 forks source link

iframe setAttribute behavior #144

Closed jshawl closed 2 weeks ago

jshawl commented 2 weeks ago

I am loving lustre! I ran into one small issue with html.iframe where a new HTTP request is made even if none of the attributes on the node change.

I think this is just a side effect of the browser's behavior:

<iframe src="./example.html"></iframe>
<script src="./example.js"></script>
<button>reset src attributes</button>
<script>
  document.querySelector("button").addEventListener("click", (e) => {
    // initiates a new HTTP request
    document.querySelector("iframe").setAttribute("src", "./example.html");

    // does not initiate a new HTTP request
    document.querySelector("script").setAttribute("src", "./example.js");
  });
</script>

but I'm wondering if this can be a feature implemented in lustre's virtual dom?

I was reading through the source and it looks like here is where the setAttribute is called - https://github.com/lustre-labs/lustre/blob/578c85bb3db98a88d8ab3533be101469c4eac7a8/src/vdom.ffi.mjs#L282

It would be awesome if iframes only called setAttribute if the next src value is different from the previous one.

Thank you!

full app example ```gleam import lustre import lustre/attribute import lustre/element.{type Element} import lustre/element/html import lustre/event // MAIN ------------------------------------------------------------------------ pub fn main() { let app = lustre.simple(init, update, view) let assert Ok(_) = lustre.start(app, "#app", Nil) } // MODEL ----------------------------------------------------------------------- type Model { Model(message: String) } fn init(_flags) -> Model { Model(message: "") } // UPDATE ---------------------------------------------------------------------- pub opaque type Msg { UserUpdatedMessage } fn update(model: Model, _msg: Msg) -> Model { model } // VIEW ------------------------------------------------------------------------ fn view(_model: Model) -> Element(Msg) { html.div([], [ html.button([event.on_click(UserUpdatedMessage)], [ element.text("trigger a Msg update"), ]), // only appears on page load html.script([], "console.log('the script was reevaluated')"), html.iframe([ attribute.attribute( "src", // appears on every button click "data:text/html,%3Cscript%3Econsole.log('the%20iframe%20rendered')%3C%2Fscript%3E", ), ]), ]) } ```
hayleigh-dot-dev commented 2 weeks ago

Ooo yep this sounds like a bug to me, I’ll make sure its fixed!

hayleigh-dot-dev commented 2 weeks ago

Fixed in v4.2.5!

jshawl commented 2 weeks ago

It works perfectly, thank you!!