Hi everyone,
I’m happy to announce the first release of ppx_deriving_melange, a Melange-compatible subset of ppx_deriving: GitHub - ahrefs/ppx_deriving_melange: Melange-compatible deriving plugins for OCaml · GitHub
Why
The original ppx_deriving can’t support Melange: it predates dune’s Melange integration — it is distributed through findlib META files, and its generated code depends on a runtime library that isn’t built in Melange mode. Melange can only link libraries that dune builds for it, so common patterns like [@@deriving eq, show] were off the table when writing frontend OCaml.
ppx_deriving_melange fills that gap: same derivers, same naming conventions and attributes, implemented on ppxlib and tested against Melange — and its generated code is self-contained, so nothing extra needs to link into your bundle.
A key use case is universal code — libraries compiled both natively and to JavaScript. Put your shared types in a library with (modes :standard melange), derive once, and the exact same equal/compare/show functions run on the server and in the browser. (This is how the project tests itself: one test-case library exercised by OUnit natively and by node on the Melange side.)
What you get
type user = {
name : string;
roles : string list;
}
[@@deriving eq, ord, show]
(* generates:
val equal_user : user -> user -> bool
val compare_user : user -> user -> int
val pp_user : Format.formatter -> user -> unit
val show_user : user -> string *)
Supported derivers in 0.1.0: eq, iter, map, ord, and show, following the native ppx_deriving conventions — including the equal, compare, and printer attribute overrides, the with_path option for show, tuples, records, (polymorphic) variants, options, lists, arrays, results, type parameters, and recursive type groups. The README documents the exact supported scope of each deriver.
Two design points worth calling out:
-
Self-contained generated code. There is no runtime library: the generated functions only use the stdlib, so the ppx is a build-time dependency only.
-
Bundle-size-aware
show. Melange compilesStdlib.Formatinto a lot of JavaScript, soshowbuilds its string directly and only falls back toFormatwhere the type requires it (custom printers, etc.). Code that only callsshowdoesn’t pull Format into your bundle;ppstays fully Format-based and native-compatible.
What’s not there (yet)
Some ppx_deriving derivers aren’t implemented yet (enum, fold, make, …), and a few type shapes are out of scope for now (ref, lazy_t, nativeint, functor-applied types). If you need one of these — or hit anything that behaves differently from native ppx_deriving — please open an issue; that’s exactly the feedback that will drive what gets built next.
Using it
opam install ppx_deriving_melange
(library
(name my_frontend_lib)
(modes melange)
(preprocess
(pps ppx_deriving_melange)))
Thanks to the ppx_deriving authors — this project follows their design and behavior closely, and includes their license attribution — and to davesnx for reviews and encouragement along the way.
Feedback, issues, and deriver requests very welcome!