package ppx_platform

Build not checked
  1. Overview
  2. Docs
Platform-specific code for native and Melange builds

Install

dune-project
 Dependency

Authors

Maintainers

Sources

ppx_platform-0.2.0.tbz
sha256=3b63eb4fc72762bedb12b51f34b05976f096916ea886ea8f54dafe22474e276d
sha512=5acbd9de60cfd026ddd92078e5943d6f3081d4299ee3ba2e2194d11e5e6a6fc93d6b0166684109bc1fd9549334e73cd6951dda0e61199ab527194038083b345d

Description

A ppx rewriter that keeps one OCaml codebase for native and Melange builds: let%browser_only, [@platform js], [@platform native] and switch%platform pick the code that each target compiles.

Added to opam-repository:

README

ppx_platform

A ppx rewriter that keeps one OCaml codebase for native and Melange builds. It picks the code that each target compiles and replaces browser-only code with a runtime failure on native.

Extracted from server-reason-react.

Install

opam install ppx_platform

Setup

Native library or executable:

(library
 (name my_lib)
 (preprocess
  (pps ppx_platform)))

Melange library: pass the -js flag to the ppx.

(library
 (name my_lib_js)
 (modes melange)
 (preprocess
  (pps ppx_platform -- -js)))

The ppx adds ppx_platform.runtime as a dependency of both builds.

Syntax

match%platform

match%platform picks one of two expressions at compile time. The cases are Native and Melange. In Reason, write switch%platform.

let api path =
  match%platform () with
  | Native -> Sys.getenv "API_URL" ^ path
  | Melange -> path

let now () =
  match%platform () with
  | Native -> Unix.gettimeofday () *. 1000.
  | Melange -> Js.Date.now ()

The ppx keeps only the branch for the current target, so each build compiles different code:

(* native *)
let api path = Sys.getenv "API_URL" ^ path
let now () = Unix.gettimeofday () *. 1000.
(* Melange *)
let api path = path
let now () = Js.Date.now ()

Both branches must have the same type, because the type checker sees only the one that remains for each target.

This lets one codebase:

  1. Behave differently on each target where it must. In api, the server needs an absolute URL, and the browser can use a relative one.
  2. Use modules that exist on one target only. In now, Unix does not exist in Melange and Js.Date does not exist on native. Each build compiles only its own branch, so neither needs the other's module.

[@melange_only] / [@native_only]

For modules and other top-level items. The item stays on one target only:

include [@melange_only] struct
  type t = Js.Json.t
end

include [@native_only] struct
  type t = Yojson.Basic.t
end

Two items with the same name are fine. Each build keeps only one of them, so the module exists on both targets:

module X = struct
  type t = Js.Json.t
end [@@melange_only]

module X = struct
  type t = Yojson.Basic.t
end [@@native_only]

melange_only

For functions and let bindings that only get compiled by Melange and are meant for the browser. On native, the body becomes an expression that raises Ppx_platform_runtime.Impossible_in_ssr, and the binding gets a melange_only alert. So native code that calls it outside another let%melange_only gets a compiler alert (an error with -alert @melange_only):

let%melange_only focus_input element = Webapi.Dom.HtmlElement.focus element

If native code calls it anyway, the exception is not caught and the program crashes. To give a fallback value instead, catch the exception:

let%melange_only window_width () = Webapi.Dom.(window |> Window.innerWidth)

let width () =
  try window_width () with Ppx_platform_runtime.Impossible_in_ssr _ -> 0

[%melange_only fun ...] does the same for an expression:

let on_click = [%melange_only fun event -> Js.log event]

[@melange_only] removes an item or a record field on native:

let window_size = (fun () -> (0, 0)) [@@melange_only]

Licence

MIT

Dependencies (4)

  1. melange >= "3.0.0"
  2. ppxlib >= "0.36.0"
  3. ocaml >= "4.14.1"
  4. dune >= "3.9"

Dev Dependencies (3)

  1. odoc with-doc
  2. ocamlformat = "0.28.1" & with-test
  3. reason with-test

Optional Dependencies

None

Used by

None

Conflicts

None

Build status

Results of building ppx_platform with each compiler on check.ci.ocaml.org, run of against opam-repository 8a77e58. All results for this package.

Each result links to its build log. To keep crawlers from overloading the site, build logs require a GitHub sign-in (see ocurrent/opam-health-check). On your first log, GitHub asks you to “Authorize opam-health-check”, the OCurrent app that runs these checks; it sees only your public profile, not your repositories. The sign-in lasts 30 days.

This version is not in the latest run; the versions below are.

Version OCaml 4.11 OCaml 4.14 OCaml 5.2 OCaml 5.4 OCaml 5.5
0.3.0 n/a good good good good
  • good Package successfully built
  • partial One of the dependencies failed to build
  • bad Package failed to build
  • n/a Package is not available in this environment
  • internal Internal failure