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

How to bind a js lib without mutating the global object. #177

Open
hhugo opened this issue Nov 19, 2024 · 3 comments
Open

How to bind a js lib without mutating the global object. #177

hhugo opened this issue Nov 19, 2024 · 3 comments
Assignees

Comments

@hhugo
Copy link
Contributor

hhugo commented Nov 19, 2024

gen_js_api seems to advertise mutating the global object in order to make js values accessible on the OCaml side using [@@js.get ], [@@js.global], ...

For example,
cat node-test/bindings/imports.mli

[@@@js.scope "__LIB__NODE__IMPORTS"]

val path: Ojs.t [@@js.global]
val fs: Ojs.t [@@js.global]

cat node-test/bindings/imports.js

globalThis.__LIB__NODE__IMPORTS = {
  path: require('path'),
  fs: require('fs'),
};

This causes problems when loading multiple js files generated by jsoo because one could override a global value with an incompatible one , see ocsigen/js_of_ocaml#1622 and ocamllabs/vscode-ocaml-platform#1617.

I'm opening this to understand if this issue has already been solved, if it has already been identified and discuss possible solutions.

Note that jsoo is able to bind to js libs relying on external primitives without mutating the global object.

@smorimoto
Copy link
Contributor

Gentle ping @mlasson

@mlasson mlasson self-assigned this Jan 13, 2025
@mlasson
Copy link
Member

mlasson commented Jan 13, 2025

Hello!

Thank you for the ping, @smorimoto, and apologies for the delay in responding to this issue.

You’re absolutely right—we need a solution that avoids mutating the global object.

Here’s a proposal that relies on stubs like imports.js:

// Provides: node_path
var node_path = require('node:path');

// Provides: node_fs
var node_fs = require('node:fs');

And the corresponding OCaml interface in imports.mli:

[@@@js.scope Ojs.runtime]

val path: Ojs.t [@@js.global "node_path"]
val fs: Ojs.t [@@js.global "node_fs"]

Here, Ojs.runtime would serve as an alias for (pure_js_expr "globalThis.jsoo_runtime").
More generally, I’m not aware of any established "good practice" for writing a js_of_ocaml library that loads modules using require in its stubs. Do you know of any examples that follow such an approach?

@mlasson
Copy link
Member

mlasson commented Jan 13, 2025

If we go this route, perhaps it would be a good idea to ask for "globalThis.jsoo_runtime" to be exposed as part of the Jsoo_runtime module ?

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

No branches or pull requests

3 participants