Why Melange

OCaml offers an industrial-strength, state-of-the-art type system and provides type inference with very few type annotations, proving invaluable in managing large projects.

JavaScript is one of the most pervasive platforms to deploy and run software. Thanks to years of efforts to improve the different VMs available, the JavaScript code running on browsers and other environments is heavily optimized and can support use cases for large products and tools.

Melange helps developers and companies bring the advantages of the OCaml platform to users of the Web platform in a way that makes it easy for developers to integrate with both ecosystems.

A bit of history

To better understand where Melange comes from, it might help to go through some of the related projects that have appeared over the last decade or so.

Js_of_ocaml

Js_of_ocaml is another OCaml to JavaScript compiler that was made public in 2011. In the presentation paper published in 2013, it is explicitly mentioned that one of its design goals was to remain as compatible as possible with the OCaml compiler, without requiring a lot of maintenance work, as the OCaml community was not excessively large at the time.

To achieve this goal, Js_of_ocaml picks the bytecode generated by OCaml batch compilation and generates JavaScript from it. OCaml bytecode has a very stable interface, so Js_of_ocaml can easily upgrade to new versions of the compiler. Due to this design decision, it can also remain compatible with most of the OCaml ecosystem, as long as the tools or libraries don’t rely on C code.

The downside of using bytecode is that it gets harder to communicate with existing JavaScript code. This is due to both the constraints on runtime representations that Js_of_ocaml can use for OCaml values, and also the compilation model used, where one bytecode program is compiled to one JavaScript program, but it is not possible to generate an individual JavaScript module from one OCaml module.

Another downside is that the resulting JavaScript is hard to read, as it is converted from a low-level representation like bytecode.

BuckleScript

Then, in 2016, Bob Zhang suggests on a Js_of_ocaml repository issue the possibility to start converting to JavaScript from an earlier stage of the compilation process, instead of using bytecode. This proposal fundamentally diverges from Js_of_ocaml original design and goals, so he starts working on what will become BuckleScript.

BuckleScript gets some inspiration from Js_of_ocaml, for example in the way that JavaScript objects are represented with Js.t. But it differs from Js_of_ocaml in many ways: it can generate more readable and lighter code. It also generates one .js file per module, which makes it easier to integrate with existing JavaScript codebases. BuckleScript puts a big emphasis on communicating with JavaScript code through a rich collection of attributes applied to external primitives.

Reason

Around the same year, a project called Reason appears at Facebook. Led by Jordan Walke, the idea is to create an alternate syntax for OCaml that is closer to C and JavaScript. Even if Reason has no take on which platform the code is deployed —native applications binaries, or web applications using JavaScript as a target language—, BuckleScript adds first class support for Reason from early on. At that point, it becomes evident that the combination of Reason with BuckleScript is a great match: BuckleScript provides tools and infrastructure to work with JavaScript ecosystem, while Reason allows developers to write their programs in a syntax they are familiar with.

Over time, and with help of other Facebook employees and the community providing bindings to pervasive JavaScript libraries like React.js with reason-react, the combination of Reason and BuckleScript gains adoption.

BuckleScript gets rebranded

However, at some point the goals of both BuckleScript and Reason projects become harder to reconcile. In August 2020, the BuckleScript team decides to rename to ReScript, stops adding support for the latest versions of the Reason parser, and replaces it with a new parser that changes the syntax. The reasons for the rebranding are explained in the official ReScript blog post.

The rebranding is trying to ease onboarding and adoption of the ReScript language, giving the project more chances to compete with mainstream compiled-to-JavaScript languages like TypeScript. However, for many existing users of BuckleScript and Reason, it is the explicit confirmation of something that had been hinted implicitly before: ReScript goals are not compatible with providing a good integration with the OCaml ecosystem.

Melange: back to OCaml

This is where Melange comes in. A few weeks after the rebranding of BuckleScript to ReScript, António Monteiro starts working on a fork of BuckleScript with a simple (not easy) goal: replace the Ninja build system, which BuckleScript had been using from its creation, with Dune, which is the most used build system for OCaml projects.

This fork of BuckleScript is later named Melange. After finishing the switch from Ninja to Dune, several additional features are added to bring it closer to OCaml. Some examples are the upgrade of the OCaml compiler version used by Melange, or modeling the changes to the OCaml compiler that Melange uses as just a plain library, instead of a full fork of the upstream compiler.

In September 2022, Ahrefs decides to invest on Melange by funding a project to deepen the integration between Dune and Melange. This project achieves its completion in Spring 2023, with the migration of Ahrefs frontend codebase to Melange and the new public releases that support it: version 3.8 of Dune and 1.0 of Melange.

Looking forward

While reaching v1.0 marks a major milestone for Melange, it is only the beginning of the journey. The Melange team remains committed to continuously improving Melange, ensuring it remains a robust and efficient tool for OCaml developers targeting the JavaScript platform. The roadmap page details past work and current goals of Melange.