Following graffiti tutorial for eliom

Hi,

I am following along the tutorial at Writing a client/server Eliom application.
I can’t compile the code because of the error :

File "graffiti.eliom", line 1, characters 12-23:
1 | open%shared Js_of_ocaml
                ^^^^^^^^^^^
Error: Unbound module Js_of_ocaml
make: *** [Makefile.eliom:169 : byte] Erreur 1

But if I try to opam install js_of_ocaml I get :

[NOTE] Package js_of_ocaml is already installed (current version is 5.7.0).

Setup :
Using ocaml 5.1.1.
eliom 10.3.1
Got the dependency by opam install ., then to fix the dependencies :

opam install ocsigen-i18n pgocaml_ppx   
opam install ocsigen-ppx-rpc

I probably miss something in the doc, but I don’t know how to debug it.

2 Likes

for the record I fixed it by using open%client Js_of_ocaml

Unbound module is likely a build system issue and not a package manager one. Do you have a makefile or a dune file ?

Nevermind, this is the correct fix.

Opening Js_of_ocaml in shared mode does not make sense, because it is the module for javascript bindings, which only make sense in the client. This was a mistake in the tutorial, the maintainers are informed and this will be fixed.

Thanks lot for finding this !

1 Like

Thank you both.
Indeed this was accepted by the old build system but not by the new dune-based one.
The tutorial is fixed.
Do not hesitate to report other problems.

1 Like

Thanks for the replies.

As of other problems, in “Drawing on a canvas”, there is a part that says

Here is the (full) new version of the program:

(I put the code at the end)
The code at this point doesn’t compile, which really confused me.
What I understood is that :

It lacks

open%server Eliom_content.Html.D

to use html.

Then there is a few value which are not yet used, which cause unused value errors.

But then

let%server main_service =
  Graffiti_app.create

is also unused.
At this point I think it is unclear what to do. I first I thought we were missing the Graffiti_app.register. At the beginning of the tuto, we do Eliom_service.create + Eliom_registration.Html.register. Then we start doing Eliom_service.create + Graffiti_app.register. At no point it is mentioned that Graffiti_app.create will create and register the service in one go.

let%server _ =
  Graffiti_app.create

works as expected.

Here’s the code :

(* Modules opened with open%shared are available in client and server-code *)
open%shared Eliom_content

open%client Js_of_ocaml
open%client Js_of_ocaml_lwt

module%server Graffiti_app =
  Eliom_registration.App (
    struct
      let application_name = "graffiti"
      let global_data_path = None
    end)

let%shared width  = 700
let%shared height = 400

let%client draw ctx ((r, g, b), size, (x1, y1), (x2, y2)) =
  let color = CSS.Color.string_of_t (CSS.Color.rgb r g b) in
  ctx##.strokeStyle := (Js.string color);
  ctx##.lineWidth := float size;
  ctx##beginPath;
  ctx##(moveTo (float x1) (float y1));
  ctx##(lineTo (float x2) (float y2));
  ctx##stroke

let%server canvas_elt =
  Html.D.canvas ~a:[Html.D.a_width width; Html.D.a_height height]
    [Html.D.txt "your browser doesn't support canvas"]

let%server page () =
  html
     (head (title (txt "Graffiti")) [])
     (body [h1 [txt "Graffiti"];
            canvas_elt])

let%client init_client () =
  let canvas = Eliom_content.Html.To_dom.of_canvas ~%canvas_elt in
  let ctx = canvas##(getContext (Dom_html._2d_)) in
  ctx##.lineCap := Js.string "round";
  draw ctx ((0, 0, 0), 12, (10, 10), (200, 100))

let%server main_service =
  Graffiti_app.create
    ~path:(Eliom_service.Path [""])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    (fun () () ->
       (* Cf. section "Client side side-effects on the server" *)
       let _ = [%client (init_client () : unit) ] in
       Lwt.return (page ()))

1 Like

Thank you very much for the report!
The Graffiti tutorial has been updated. It should be much better now.
It was not working well with the new build system.
Do not hesitate to report other problems.

1 Like

I did the whole tutorial in one go with the new version, didn’t found problems.
I don’t need it, but when clicking one the “switch to Reason syntax button”, there is some

(* Error while translating to Reason *) 

Thanks for the quick replies, and for fixing the tutorial. Seing it in action this framework is even more interesting than I thought.

1 Like

Thank you!

Indeed we are using the OCaml to Reason converter provided by Reason but it fails on some examples. May be we could remove the conversion feature. I’m not even sure it is up to date. I’m wondering whether some people are still using the Reason syntax.