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

Should jsoo-react vendor react.js? #104

Open
jchavarri opened this issue Jan 5, 2022 · 3 comments
Open

Should jsoo-react vendor react.js? #104

jchavarri opened this issue Jan 5, 2022 · 3 comments

Comments

@jchavarri
Copy link
Collaborator

Right now, jsoo-react calls require to bring react.js libraries:

let react : react = Js_of_ocaml.Js.Unsafe.js_expr {|require("react")|}
let reactDom : reactDom = Js_of_ocaml.Js.Unsafe.js_expr {|require("react-dom")|}

This means that users of the library are forced to use some JavaScript bundler like Webpack to resolve these requires with the actual library code.

But we could instead vendor a version of React.js and connect OCaml bindings with the JavaScript library objects internally, without exposing all this connection details to end users. This is what some OCaml projects have been doing, like virtual_dom, that uses browserify to bundle the JavaScript library.

Upsides of vendoring:

  • No need to use Webpack or any bundler on client
  • More controlled environment (less chances of things going wrong as less parts required)
  • Simpler setup, templates, etc
  • Faster iteration loops

Downsides:

  • Vendoring would require to put React.js entry points (library objects) in some field under global jsoo_global_object with all the downsides that relying on globals bring.
  • It also means that there is less flexibility for users to decide which version of React.js they want to use. E.g. right now jsoo-react supports v16, but some user could start using v17 for some reason just by updating their package.json.

I guess it all comes down to how "close" to JavaScript ecosystem a project is: for projects leveraging a lot of JS related tooling, using Webpack or other bundler is not a pain (actually helps). But for projects leaning more on OCaml side, with very few JavaScript dependencies, adding bundler is actually overkill.

Any other things? What do you think?

@glennsl
Copy link
Contributor

glennsl commented Jan 5, 2022

Apologies in advance for the stream of thoughts below. I'm still very new to JSOO, and just throwing ideas out there in the hopes that something might stick. Feel free to ignore if it makes no sense :)

It also means that there is less flexibility for users to decide which version of React.js they want to use. E.g. right now jsoo-react supports v16, but some user could start using v17 for some reason just by updating their package.json.

You could always just fork jsoo-react entirely and replace the vendored library. Not sure that's necessarily a bad thing even, as it's not unlikely that other changes are needed as well in order to benefit from the upgrade. It also makes it easier to reason about backwards compatibility when it's tied to a single version.

Not an approach I'd recommend for every binding library, but for something as fundamental as react it might make sense.

Alternatively I wonder if it's possible to inject the dependency somehow. For example, ignoring the general awkwardness and the need to completely restructure jsoo-react, it might be possible to use a functor:

(* react.ml *)
include JsooReact.Make(struct 
  let react : react = Js_of_ocaml.Js.Unsafe.js_expr {|require("react")|} 
  let reactDom : reactDom = Js_of_ocaml.Js.Unsafe.js_expr {|require("react-dom")|} 
end)

Or maybe publish separate packages, using dune to conditionally compile it as vendored, so it could be opted into.

(In Rust I'd use "features" for this, but for OCaml that would require both opam and dune, at the very least, to agree on a protocol for this)

@jchavarri
Copy link
Collaborator Author

Thanks for sharing your thoughts @glennsl.

I remembered now why I went for current approach using require. 😅

The main downside of vendoring react js library is that then all React code gets processed by js_of_ocaml JavaScript parser. I remember having some issues with global this object while trying, but maybe it does not happen now, would be nice to give it a try. What I remember is that this would increase build time significantly, in both development and release Dune profiles.

So, I ended up going for the require approach for the following reasons:

  • Projects using jsoo-react will very likely use some React components library. As soon as they do so, these projects will need to use Webpack or some other bundler because js_of_ocaml will not be able to parse jsx code or any other non-standard JavaScript syntax "extensions". I believe js_of_ocaml will never add support for this kind of things, nor should it.
  • Vendoring implies that any future upgrades made to React.js can break, if js_of_ocaml parser is not able to parse React code for some reason (e.g. es6 modules? idk). Note parsing issues can arise from either React or any of its dependencies (it only has loose-envify and object-assign though)

Point 2 is pretty minor, but I think point 1 makes it very likely that consumers will need Webpack or some other bundler. I am happy to consider the proposal and build some proof of concept if there are specific cases out there of projects that use jsoo-react but don't need any other JavaScript/React dependencies :)

What do you think?

@glennsl
Copy link
Contributor

glennsl commented Jan 9, 2022

Hmm, why would it have to process the JavaScript? And why would that be slower than webpack? I naively thought it would just be a matter of concatenation with a bit of wrapper code to glue things together.

Projects using jsoo-react will very likely use some React components library. As soon as they do so, these projects will need to use Webpack or some other bundler because js_of_ocaml will not be able to parse jsx code or any other non-standard JavaScript syntax "extensions".

I'm not sure that's true. Although I'm not a big consumer of third-party react components myself, so who knows. It certainly wouldn't be the weirdest thing I've encountered in the JavaScript universe. But why would you package the raw source code, and require consumers to use all of your builld-time tools, rather than package the processed JavaScript?

A third option might be to use <script> tags. I don't know how common it is to do this anymore, but react is at least still built for it. That would allow a bundler to be sued, but not require it, and gives the consumer even more flexibility in managing their dependencies.

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

2 participants