eliom icon indicating copy to clipboard operation
eliom copied to clipboard

Client closure XXX not found

Open sagotch opened this issue 8 years ago • 5 comments

My compilation instructions:

js_of_eliom -rectypes -ppx -o local/var/www/twittex/eliom/twittex.js  -package lwt.ppx -package js_of_ocaml.ppx -package js_of_ocaml.deriving.ppx -package ocsature.client -package markiz  \
          _client/twittex.cmo
eliomc -rectypes -ppx -a -o local/lib/twittex/twittex.cma  \
          _server/twittex.cmo

This code:

  let btn label t =
    button ~a:[ (* a_onclick [%client fun _ -> *)
      (*   let e = Eliom_content.Html.To_dom.of_textarea ~%editor in *)
      (*   let b = e##.value##substring 0 e##.selectionStart in *)
      (*   let s = e##.value##substring e##.selectionStart e##.selectionEnd in *)
      (*   let a = e##.value##substring e##.selectionEnd e##.value##.length in *)
      (*   e##.value := *)
      (*     b##concat_4 (Js.string @@ "{" ^ ~%t ^ " ") s (Js.string " }") a *)
      (* ]  *)]
      [ pcdata label ]
  in

Result in an error if I uncomment the commented section:

[eliom:client] Client closure 0gsFm82 not found  (is the module linked on the client?)
Uncaught (3) [0, Array(3), bC]

NB: In the same code, I use a a_oninput attribute that works just fine.

It really make no sens to me. And it obviously also make my website impossible to run. Is there any missing flag to my compilation ? (no package is pinned, I only have a "eliom" {>= "6.2"} constraint)

sagotch avatar Jul 22 '17 11:07 sagotch

Your compilation instructions look OK, but they are not complete, so I can't tell if anything is missing. How have the _client/twittex.cmo and _server/twitter.cmo been produced? Are you using the standard makefile that we distribute via eliom-distillery?

Where do you call btn?

vasilisp avatar Jul 22 '17 21:07 vasilisp

The full compilation process (after a make clean)

ju:~/workspace/twittex$ make
eliomc -rectypes -ppx -infer -package lwt.ppx -package js_of_ocaml.deriving.ppx -package ocsature.server -package markiz twittex.eliom
js_of_eliom -rectypes -ppx -c -package lwt.ppx -package js_of_ocaml.ppx -package js_of_ocaml.deriving.ppx -package ocsature.client -package markiz  twittex.eliom
js_of_eliom -rectypes -ppx -o local/var/www/twittex/eliom/twittex.js  -package lwt.ppx -package js_of_ocaml.ppx -package js_of_ocaml.deriving.ppx -package ocsature.client -package markiz  \
          _client/twittex.cmo
There are some missing primitives
Dummy implementations (raising 'Failure' exception) will be used if they are not available at runtime.
You can prevent the generation of dummy implementations with the commandline option '--disable genprim'
Missing primitives:
  caml_channel_descriptor
  re_search_forward
  unix_close
  unix_connect
  unix_geteuid
  unix_gethostbyname
  unix_gethostname
  unix_getpid
  unix_getppid
  unix_getpwuid
  unix_lockf
  unix_set_close_on_exec
  unix_socket
  unix_string_of_inet_addr
  unix_times
eliomc -rectypes -ppx -c -package lwt.ppx -package js_of_ocaml.deriving.ppx -package ocsature.server -package markiz  twittex.eliom
eliomc -rectypes -ppx -a -o local/lib/twittex/twittex.cma  \
          _server/twittex.cmo
eliomopt -rectypes -ppx -c -package lwt.ppx -package js_of_ocaml.deriving.ppx -package ocsature.server -package markiz  twittex.eliom
eliomopt -rectypes -ppx -a -o local/lib/twittex/twittex.cmxa  \
          _server/twittex.cmx
eliomopt -rectypes -ppx -shared -linkall -o local/lib/twittex/twittex.cmxs  local/lib/twittex/twittex.cmxa
ju:~/workspace/twittex$ 

And the code of the whole app:

open%shared Eliom_content.Html.D

module Twittex_app =
  Eliom_registration.App
    (struct
      let application_name = "twittex"
      let global_data_path = None
    end)

let main_service =
  Eliom_service.create
    ~path:(Eliom_service.Path [])
    ~meth:(Eliom_service.Get Eliom_parameter.unit)
    ()


let%client rec render_document doc =
  let out = Buffer.create 1024 in
  List.iter (block out) doc ;
  Buffer.contents out

and block out = function
  | `H (i, content) ->
    Buffer.add_string out ("<h" ^ (string_of_int i) ^ ">") ;
    inlines out content ;
    Buffer.add_string out ("</h" ^ (string_of_int i) ^ ">")
  | `P content ->
    Buffer.add_string out "<p>" ; inlines out content
  | `UL list ->
    Buffer.add_string out "<ul>" ; list_item_list out list
  | `OL list ->
    Buffer.add_string out "<ol>" ; list_item_list out list

and inlines out content : unit = List.iter (inline out) content

and list_item_list out =
  List.iter @@ fun (`LI (content, children) ) ->
  Buffer.add_string out "<li>" ;
  inlines out content ;
  match children with
  | None -> ()
  | Some children -> block out (children :> Markiz.block)

and inline out = function
  | `IMG url ->
    Buffer.add_string out @@
    "<img src=\"" ^ url ^ "\" alt=\"" ^ url ^"\"/>"
  | `TEXT txt ->
    Buffer.add_string out txt
  | `TAG (t, content) ->
    Buffer.add_string out ("<"^t^">") ;
    inlines out content ;
    Buffer.add_string out ("</"^t^">")
  | `LINK (uri, content)
    ->
    Buffer.add_string out ("<a href=\""^uri^"\">") ;
    inlines out content ;
    Buffer.add_string out "</a>"

(* https://www.w3.org/TR/html5/syntax.html#optional-tags *)
let%client render s =
  let doc = Markiz.parse (Stream.of_bytes s) in
  (render_document doc)

let editor =
  let renderer = div
      ~a:[ a_style
             "float:left;border:1px solid red;width:400px;height:600px"] [] in
  let editor =
    textarea ~a:[ a_style
                    "float:left;border:1px solid black;width:400px;height:600px"
                ; a_oninput [%client fun ev ->
                    let input = (Obj.magic ev##.target)##.value in
                    let rendered = Js.string (try render (Js.to_string input)
                                              with _ -> "") in
                    (Eliom_content.Html.To_dom.of_div ~%renderer)##.innerHTML
                    := rendered ] ]
      (pcdata "")
  in

  let btn label t =
    button ~a:[ (* a_onclick [%client fun _ -> *)
      (*   let e = Eliom_content.Html.To_dom.of_textarea ~%editor in *)
      (*   let b = e##.value##substring 0 e##.selectionStart in *)
      (*   let s = e##.value##substring e##.selectionStart e##.selectionEnd in *)
      (*   let a = e##.value##substring e##.selectionEnd e##.value##.length in *)
      (*   e##.value := *)
      (*     b##concat_4 (Js.string @@ "{" ^ ~%t ^ " ") s (Js.string " }") a *)
      (* ]  *)]
      [ pcdata label ]
  in
  div [ div [ div [ btn "Bold" "b"
                  ; btn "Italic" "i"
                  ; btn "Underline" "u" ]
            ; editor ]
      ; div [ renderer ] ]

let () =
  Twittex_app.register ~service:main_service @@ fun () () ->
  let head = head (title @@ pcdata "twittex") [] in
  let body = body [ h1 [ pcdata "Welcome to \"Ocsature.\" template!" ]
                  ; editor ] in
  Lwt.return @@ html head body

Makefile is from https://github.com/sagotch/ocsature project template, which is a simpler version of ocsigen-start template.

sagotch avatar Jul 23 '17 11:07 sagotch

Try with let editor () = ....

vasilisp avatar Jul 23 '17 14:07 vasilisp

Oh come on... That's the same problem as the last time, how couldn't I see it...

It still is very strange regarding what causes the app to work or not.

Anyway, thanks for the tip!

Note: related to https://github.com/ocsigen/eliom/issues/506

sagotch avatar Jul 23 '17 14:07 sagotch

Certain operations need to happen while serving a request. These are frequently implicit and not at all evident from the source code. We need to formalize and document what can only be done while serving a request (not trivial). But as a rough guideline, producing part of your tree as a global value (like editor) is not guaranteed to work.

vasilisp avatar Jul 23 '17 16:07 vasilisp