My web-app server is Rails, but it needs to execute Reason code (pure, stateless) for certain requests. This code is wrapped in an HTTP endpoint with bs-express and runs on Node on the same box. The Rails server talks to it locally.
The web UI is part of the Rails codebase, and it is written in ReasonReact. There is also a web-worker that is almost identical to the Node server. But this one runs on the browser.
All three of them - Node, webworker, and ReasonReact UI - relies on a common Reason codebase.
It is structured like this:
rails/
bsconfig.json
app/javascript
web-ui/
common-core/
node/
bsconfig.json
The Node source tree is within the Rails directory. It is a thin folder with just an HTTP entrypoint. All other code is in common-core. Its bsconfig.json looks like this:
"sources": [
...
{
"dir": "../app/javascript/common-core",
"subdirs": true
}
]
This required a non-standard Rails deployment: a single git repo that serves two applications. But no other hacks.
Modules in common-core
serialize and deserialize data with bs-json. This is possible since all Reason code runs on a Javascript runtime - either on Node or browser. This means I don’t have to worry about keeping two schemas in sync, which would’ve been the case if I had opted for OCaml and atdgen instead of Node. But @Khady recently wrote a BuckleScript backend for atdgen (https://github.com/ahrefs/bs-atdgen-codec-runtime) so this might no longer be a concern.
I would’ve liked to switch to native OCaml instead of Node on the backend, but it is unclear how I can use the same unmodified code and standard library on both OCaml and Javascript runtimes. This setup has worked well so far - it is really nice to be able to use the exact same types and code everywhere and not duplicate anything.