Skip to content

sketch_lustre.ssr crashes with ets.lookup Erlang error #45

@kwshi

Description

@kwshi

summary

I'm trying to render a lustre document directly to string, SSR style. This works fine when using lustre on its own, using something to the effect of

import lustre/element
import lustre/element/html
import gleam/io

pub fn main() {
  html.html(...)
  |> element.to_document_string()
  |> io.println
}

However when using sketch and sketch_lustre this results in the program crashing at runtime error with the following stack trace:

runtime error: Erlang error

An error occurred outside of Gleam.

erlang:error(Badarg)

stacktrace:
  ets.lookup unknown source
  sketch_global_ffi.get_stylesheet /root/lustre_bug/build/dev/erlang/sketch_lustre/_gleam_artefacts/sketch/lustre/internals/sketch_global_ffi.erl:39
  sketch/lustre/element.class_name src/sketch/lustre/element.gleam:82
  sketch/lustre/element.element src/sketch/lustre/element.gleam:37
  lustre_bug.-render_sketch_ssr/0-fun-0- src/lustre_bug.gleam:33
  sketch/lustre.ssr src/sketch/lustre.gleam:219
  lustre_bug.main src/lustre_bug.gleam:74

It's possible this is because I am not setting up/initializing the stylesheet correctly. However I am trying to follow the examples given in the sketch_lustre documentation and on the sketch homepage to the best of my ability-- as an aside, both of those example code snippets are in fact broken and do not compile on latest versions.

detailed explanation/troubleshooting/reproduction

Anyway, I threw together a reproduction of the issue to explain what I tried and what's breaking in more detail: https://github.com/kwshi/bug-reports/tree/main/gleam-sketch-lustre-ssr. I'm also pasting the code here for your reference:

import argv
import gleam/io

import lustre/element
import lustre/element/html

import sketch
import sketch/css
import sketch/lustre as sketch_lustre
import sketch/lustre/element/html as sketch_html

fn render_vanilla() {
  html.html([], [
    html.head([], [html.title([], "hello lustre")]),
    html.body([], [html.text("foo bar")]),
  ])
}

fn render_sketch_ssr() {
  use <- sketch_lustre.ssr()
  sketch_html.html([], [
    sketch_html.head([], [sketch_html.title([], "hello lustre")]),
    sketch_html.body(css.class([css.color("red")]), [], [
      sketch_html.text("foo bar"),
    ]),
  ])
}

fn render_sketch_manual(stylesheet: sketch.StyleSheet) {
  use <- sketch_lustre.render(stylesheet, [sketch_lustre.node()])
  sketch_html.html([], [
    sketch_html.head([], [sketch_html.title([], "hello lustre")]),
    sketch_html.body(css.class([css.color("red")]), [], [
      sketch_html.text("foo bar"),
    ]),
  ])
}

fn render_mix_ssr() {
  use <- sketch_lustre.ssr()
  render_vanilla()
}

fn render_mix_manual(stylesheet: sketch.StyleSheet) {
  use <- sketch_lustre.render(stylesheet, [sketch_lustre.node()])
  render_vanilla()
}

fn render(stylesheet: sketch.StyleSheet) {
  case argv.load().arguments {
    ["vanilla"] -> render_vanilla()
    ["sketch-ssr"] -> render_sketch_ssr()
    ["sketch-manual"] -> render_sketch_manual(stylesheet)
    ["mix-ssr"] -> render_mix_ssr()
    ["mix-manual"] -> render_mix_manual(stylesheet)
    _ ->
      panic as "invalid case: run with one of `vanilla`, `sketch-ssr`, `sketch-manual`, `mix-ssr`, `mix-manual`"
  }
}

pub fn main() {
  let assert Ok(stylesheet) = sketch_lustre.setup()

  render(stylesheet)
  |> element.to_document_string
  |> io.println
}

Basically, here are five different variations of the same basic render function:

  • render_vanilla is the plain lustre version without sketch
  • render_sketch_ssr renders elements using sketch/lustre/element/html wrapped with sketch/lustre.ssr
  • render_sketch_manual renders elements using sketch/lustre/element/html wrapped with sketch/lustre.render
  • render_mix_ssr renders elements using plain lustre/element/html but wraps it in sketch/lustre.ssr anyway, because I guess why not
  • render_mix_manual renders elements using plain lustre/element/html wrapped with sketch/lustre.render

The last two are maybe kind of pointless but I included anyway just to poke around. The first (vanilla) is included just to demonstrate that things work fine without sketch. The ssr example results in the crash, whereas the manual example does not. It looks from the source code that ssr is essentially just calling render behind the scenes after retrieving the stylesheet from some global store (via global.get_stylesheet()) which is supposed to be created by setup, and this appears to be what's broken, as also indicated by the error stacktrace.

Anyway, please let me know if this is a bug, or if I'm just missing something about the correct way to use sketch. I am new to Gleam and have also never worked with any of the other BEAM languages before (Elixir, Erlang) so I also don't really understand how to troubleshoot these errors occurring seemingly outside Gleam and rather in the Erlang runtime; narrowing it down to get_stylesheet/set_stylesheet seems to be the best guess I've got.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions