Hi everyone,
I am an OCaml beginner and I’m currently implementing a proof-of-concept full-stack web application with Melange. I’m using dune 3.18.0
.
The frontend (see lib/frontend
) is an Elm-like application using melange-tea
because I like Elm. It displays a button and when clicked queries a list of JSON objects from the backend. The backend (see lib/backend
) is written with dream
. Both frontend and backend define type Animal.t
for data exchange. I’m using melange-json
(and melange-json-native
) to derive JSON encoders and decoders on both the frontend and backend. Also, I’m using esbuild
and dune’s Resource bundling mechanism to generate a single Javascript file and bundle it with the executable (see lib/backend/dune
).
So far so good. It was a relatively pleasant learning experience.
As a next step, I wanted to move the Animal.t
type and the JSON encoding / decoding into a shared (a.k.a. universal) library, see branch shared-library. This is where I got stuck.
I read the “A Preview of Universal Libraries in Dune” article, so I wrote lib/shared/dune
like this:
(library
(name shared)
(libraries melange-json-native)
(modules animal)
(preprocess (pps melange-json-native.ppx))
(enabled_if
(= %{context_name} default)))
(library
(name shared)
(libraries melange-json)
(modules animal)
(modes melange)
(preprocess (pps melange.ppx melange-json.ppx))
(enabled_if
(= %{context_name} melange)))
I got the following compiler error:
Error: The library `shared` was added as a dependency of a `melange.emit`
stanza, but this library is not compatible with Melange. To fix this, add
`melange` to the `modes` field of the library `shared`.
It seems like the melange.emit
stanza is executed in the default
context where only the first definition of the shared
library is visible, and that one does not define (modes melange)
.
The next thing I tried was to add the enabled_if
flag to melange.emit
too to make sure it only runs in the melange
context. This gave me the following error:
File "lib/backend/dune", lines 5-13, characters 0-219:
5 | (rule
6 | (deps (alias ../../melange))
7 | (action
8 | (with-stdout-to
9 | assets.ml
10 | (progn
11 | (echo "let js = {|")
12 | (run esbuild --bundle --minify --format=esm ../../output/lib/frontend/frontend.js)
13 | (echo "|}\n")))))
Error: No rule found for alias melange
So now apparently I lost my ability to specify the melange compilation step as a dependency of the bundling rule. But without this dependency the backend will be compiled before the Javascript code (and hence the Assets
module) is generated.
Is there another way to tell dune what I want? Or am I too early in the melange development process for this kind of stuff (full-stack application in one package + resource bundling at compile time)?