Since last September, the Melange, Dune, and Ahrefs development teams have been working to enhance the integration between Dune and Melange. As a company that uses a lot of OCaml in the backend, Ahrefs saw an opportunity to bring its frontend stack closer to OCaml by using Melange while still integrating with the JavaScript ecosystem of UI libraries. Thus, the company decided to invest and actively participate to make this integration happen.
I am happy to announce we achieved a significant milestone in this integration process: we transitioned all Ahrefs frontend projects to use Melange. We have explained this transition in detail in a blog post:
Regarding the current state of Melange, it’s worth noting that our focus thus far has been on designing and implementing the Dune-Melange integration and applying it within Ahrefs. The goal has been to demonstrate that the toolchain can scale and be used in mid-large codebases, and the result has been successful so far. The process has been beneficial not only for Melange but also for Dune itself, as we were able to identify and address some performance issues, including a significant performance fix that made some build commands nearly 10 times faster in our case.
While we’ve made significant progress with the Dune-Melange integration, we recognize that there is still work to be done to improve the documentation and developer experience. Currently, Melange lacks a dedicated documentation site, and the latest functionality isn’t yet available in published versions of Dune and Melange on the opam repository.
We’re actively working to address this, but in the meantime, we invite those who are adventurous to explore the melange-opam-template and review the newly added melange.emit stanza documentation found in the latest version of Dune’s documentation. If you have any questions, encounter any issues, or otherwise want to participate in any way, we invite you to join the #melange channel in the Reason Discord.
Thank you for taking the time to read about our progress with the Dune-Melange integration. We hope you share our excitement about this project!
I guess this is expected. It is a recent project, and up until now the focus has been on making sure the idea is feasible and it works. With the first iteration of Melange, @anmonteiro proved that it was possible to upgrade the project to be compatible with the most recent versions of the OCaml compiler, and also model it as a “compiler libs” library, rather than a full fork. It also integrated with Dune, but at a raw level: Melange would generate rules for Dune to execute, but there was no concept such as libraries and such yet. The second phase, which has been completed recently, has proven that a deeper integration with Dune was possible and Melange is usable in large projects. I guess we are entering now a third phase of the project which will consist on documenting the toolchain, as well as porting over existing libraries and bindings, so other people can start using it easily.
Besides the points you mentioned, I’d like to mention a couple more:
One of the biggest upsides imo is having access to the OCaml editor platform. Years of effort in Merlin, OCaml LSP and extensions like vscode-ocaml makes the Melange developer experience really ergonomic.
Another difference is how package management is handled: while with ReScript every dependency can be downloaded with just npm, Melange projects will have to use opam and npm. This is a trade-off: on one hand, most Melange projects will have to deal with both package.json and opam files. But on the other hand they can benefit from opam’s source-based package distribution model for things like PPXs, linters, or any other OCaml tooling. By comparison, consuming any OCaml ecosystem tool in ReScript is more challenging. As npm is a package manager designed for an interpreted language, distribution requires using prebuilt binaries. And the fact that it is based on a now quite old version of the compiler does not make things easier.
I think this is caused by a combination of factors affecting compilation times. Some of them can be solved, some of them are by design:
Dune’s design requires walking the whole project tree when building it to find dune files. ReScript, as it’s based on Ninja, can read all the project information in a centralized way, from a single file.
Dune doesn’t use file modification times, but rather calculates changes digesting a hash from the file contents.
Integration with Dune forced Melange to build things in a more “staged” way, so that object files (cmj) and resulting JavaScript files can be generated in 2 steps.
ReScript optimizes the way the module dependencies of a given module are calculated by caching the results, Melange uses ocamldep through its integration with Dune and this step is not optimized / cached.
ReScript has a “tighter” design, which provides more opportunities to optimize things like the ReactJS ppx, which can be “fused” with the compiler. On the other hand, Melange prioritizes extensibility and ecosystem integration, so the ReactJS pre-processing is done through a regular PPX.
I am sure there are many other things that I am not aware of, maybe someone with more knowledge can add or refine the points above
Again, probably missing some things, but from the top of my head:
Melange won’t support anything running on OCaml 5 (yet).
Thanks for the clarification, I was not aware of that part. Would it be more accurate to describe how Dune works as follows?
Dune does not rely solely on file modification times to infer that a file has changed and needs to be rebuilt, but it adds another check based on the file content hash.
I understood this two-steps approach is beneficial when some tools change the modification time, but the content remains the same as the last build, like when checking out branches with git.