My guess is that .eml files cannot be expressed on top of the OCaml AST. The OCaml compiler has to be able to parse the file before a PPX can process it; see Preprocessors and PPXs · OCaml Tutorials. Specifically, <html> and <body> do not seem like valid OCaml syntax.
Strictly speaking that’s not true, the use of .eml just seems to be a particular opinionated choice adopted by the dream developers.
While ppxs do need to be able to parse the file using standard ocaml syntax, you can somewhat escape the system by embedding your language within a string constant to be processed at compile time — the {<name>| ...|<name>} syntax format is a nice convention for highlighting that in the source code; A proper ppx-embedding is provided by ocsigen’s ppx for html (as mentioned by @yawaramin ):
let content = [%html{|<div id="content">some content</div>|}] ;;
val content : [> Html_types.div ] Html.elt
Personally, I don’t like this style because it means that your editor is unable to provide any support for editing within the embedding code (because it is seen as just a string content), but this same limitation applies to Dream’s eml approach, so it’s not clear what’s being gained here.
Edit: @zeroexcuses , the tyxml-ppx ppx might be what you’re looking for (see above)
Yes, I use tyxml-jsx and .re files, but strictly for HTML templating – all of my types and “real” logic remains in OCaml syntax, as I fundamentally can’t stand Reason syntax outside of its support for HTML literals.