#Lustre client components in server components

1 messages · Page 1 of 1 (latest)

simple delta
#

Hi all, I've been playing around with lustre recently and am trying to prototype having a client component rendered from a server component. The basic idea is that I would like to render most things with server components but in certain cases, have a component render on the client where it makes sense for latency/ux reasons. Ideally at some point I would just have a client_component("SomeComponent", data) function that I can call from the server view that takes care of all the details.

Does anyone know if this is possible or has anyone achieved this?

I have a project with separate client and server directories, and I have a sample client lustre app that should get mounted to #app when main is called.

// client
pub fn main() -> Nil {
  echo "client main function is running!"

  let app = lustre.element(html.text("Hello, world!"))
  let assert Ok(_) = lustre.start(app, "#app", Nil)

  Nil
}

When the client.mjs is built, it is placed in the server priv/static folder and loaded via script src="..." tag from my server component's view function:

// server
fn view(model: Model) -> Element(Msg) {
  div([], [
    ...
    element.element("div", [attribute.id("app")], []),
    script([src("/static/client.mjs")], ""),
  ])
}

But in the browser I see nothing is rendered and the following console log

src/client.gleam:13
"client main function is running!"

Uncaught TypeError: document is not a function
    at is_browser (client.mjs:4502:26)
    at start3 (client.mjs:4758:6)
    at main (client.mjs:4771:15)
    at client.mjs:4925:1
is_browser @ client.mjs:4502
start3 @ client.mjs:4758
main @ client.mjs:4771
(anonymous) @ client.mjs:4925

Interestingly, I am able to make this work when I place the #app div and script outside of the server component, but not when rendered from the server component.

thick rapids
#

hi! your client.mjs is a Javascript Module. Since they didn't always exist you have to tell the browser to load your script using module semantics explicitely, by setting type="module" on your script tag.

#

I'd also recommend using lustre's support for custom elements instead of including the element and script like that 🙂