Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE REQUEST] allow ECMAScript import and export when defining jsoo stubs #1532

Open
hhugo opened this issue Nov 19, 2023 · 5 comments
Open

Comments

@hhugo
Copy link
Member

hhugo commented Nov 19, 2023

This this possible now that #1529 is here.

@Fizzixnerd
Copy link

I'd like to see this feature implemented. I have lots of functional programming experience, though I'm new-ish to ocaml (I come from a mostly Haskell and F# background). I'd like to give this a shot, but would need some direction definitely to at least getting started. If anyone is able to provide such direction, I would be greatly appreciative. I cannot seem to find out where on Matrix/IRC I should go for a more realtime chat experience either, but that could be because no such channel exists. I will think a bit about a more details spec on what I'd imagine this feature to look like.

@Fizzixnerd
Copy link

Fizzixnerd commented May 11, 2024

One of the first things I think needs to be decided is: can we treat ES6 static module imports as OCaml modules? Harder still: should we?

Ultimately, I currently think we shouldn't. It is unclear if it's even possible today, and it's certainly unclear if it will remain possible indefinitely in the future as ES changes. ES is fundamentally a more dynamic language than OCaml, and I think just accepting that and thinking of ES modules as more akin to (ocaml) objects than (ocaml) modules is probably for the best.

Instead, I think a general ES module should be represented as an OCaml object, and so the "types" of ES modules are just classes.

That is, binding to an ES module should be as easy as declaring an OCaml class (or perhaps class type) stub.

As an example taken from https://pixijs.com/8.x/playground?exampleId=basic.container of something I'd ultimately like to be able to do:

open Js_of_ocaml

(* For application below *)
type init_args = {
    background : js_string optdef;
    resizeTo : js_any optdef
}

(* Binding for the Application class *)
class%js.class type application = object 
    method init : init_args Js.t -> unit js_promise
    val stage : js_any (* etc. *)
    val ticker : js_any (* etc. *)
    val canvas : js_any (* etc. *)
    (* ... *)
end

class%js.class type assets = .. (* ... *)
class%js.class type container = .. (* ... *)
class%js.class type sprite = .. (* ... *)

(* Uses the same rules for underscores as described in https://ocsigen.org/js_of_ocaml/latest/manual/bindings *)
class%js.module type pixi = object
    val _Application : application
    val _Assets : assets
    val _Container : container
    val _Sprite : sprite
    (* Any object that extends this type would be okay too, which is nice for writing stubs! *)
end

(* I added an annotation/extension since it might be easier to label these in terms of lifting them all to the top of the file or whatever... *)
let%js.import pixijs = Js.Unsafe.Import.(static (star ~import_as:"PIXI" ()) "pixi.js")

let _ =
    let f = fun%js.async () ->
        let app = new%js pixi._Application in
        let%js.await _ = app#init({ background = Js.string "#1099bb"; resizeTo = Js.Unsafe.global }) in
        Js.Unsafe.global##.document##.body##appendChild app.canvas
        (* ... snip ... see above link *)
        app.ticker#add
            (* this annotation makes sure the fun is in a non-curried js-style.  Not sure if such a feature already exists *) 
            (fun%js time ->
                container.rotation <- container.rotation -. 0.01 *. time##.deltaTime)
    in
        Js.Async.no_wait f () (* For the async IIFE *)

Looking forward to hearing your criticisms; I have found using js_of_ocaml incredible and pleasant for working with ocaml code, but somewhat less pleasant when trying to make/use bindings and extant js libraries from ocaml. I'd like to help bridge the gap!

@Fizzixnerd
Copy link

ping @hhugo ; if this isn't a good time just let me know and I'll direct my efforts elsewhere ^_^

@hhugo
Copy link
Member Author

hhugo commented May 15, 2024

I thinks there is a misunderstanding here. This issue was about being able to import/export inside js stubs (e.g. in https://github.com/ocsigen/js_of_ocaml/blob/master/runtime/compare.js). In particular, using export instead of using magic comment such as //Provides: ***

You seem to be interested in using import on the OCaml side.

  • You should open a new issue (or maybe many, see point bellow).
  • Your example introduced many new things which seem unrelated to the main request (class%js.class type, class%js.module type, let%js.await, fun%js.async, fun%js).
    • class%js.class type and class%js.module type, I don't understand what the extension point is supposed to do. Binding a JS object describe how to bind a JS object.
    • fun%js, seems to be Js_of_ocaml.Js.wrap_callback or maybe Js_of_ocaml.Js.Unsafe.callback
    • maybe open a separate issue for async/await

@Fizzixnerd
Copy link

Will open new issues, thanks for the clarification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants