Sesame x OCurrent

Sesame is a platform-agnostic tool providing a set of utilities for building websites. OCurrent is a tool for building data-graphs expressing inputs and outputs to achieve incremental computation.

Current_sesame is the bringing together of OCurrent and Sesame to build incremental site generators.

Collections

Just like Sesame.Collection, Current_sesame exposes an OCurrent-powered version via to Current_sesame.Make functor. Part of Sesame's redesign was to ensure some of the modules over in Sesame provided the functionality needed to work with OCurrent's caching model.

You can now specify things like:

(* A simple current-sesame pipeline that generate HTML 
 from jekyll-format files and comes complete with hot-reloading *)

module Meta = struct
  type t = { title : string } [@@deriving yaml]
end

(* First some boiler-plate to get the modules we need *)

(* Plain old Sesame modules that build a collection from a 
   file and HTML from a collection *)
module C = Sesame.Collection.Make (Meta)
module H = Sesame.Collection.Html (Meta)

(* OCurrent-powered versions with cachine and incremental building *)
module CC = Current_sesame.Make (C)
module HC = Current_sesame.Make (H)

Building the resulting collection is then possible with a bit of OCurrent magic :) We can even add a little watcher to get some hot-reloading goodness.

let watcher = Current_sesame.Watcher.create ()

(* ~~~ The pipeline ~~~ *)
let pipeline dst () =
  (* Build a collection and pass in the watcher to record the association *)
  let c =
    CC.build ~watcher ~label:"fetching collection"
      (Fpath.v "data/index.md" |> Current.return)
  in
  (* Build the HTML from the collection using the default build functionality from Sesame *)
  let html = HC.build ~label:"building html" c in
  (* Save the HTML string to a file *)
  Current_sesame.Local.save (Fpath.(dst / "index.html") |> Current.return) html

After that you just add the traditional OCurrent boiler-plate and a little bit of mangling to get the Lwt_condition.t variable to our development server and you are done!

let main dst =
  let dest = Fpath.v dst in
  (* The OCurrent Engine *)
  let engine = Current.Engine.create (pipeline dest) in
  (* Tell the watcher to watch our data directory and get back
     a condition variable that is broadcast to on changes *)
  let f =
    Lwt.map
      (fun (f, cond, _) -> (f, cond))
      (Current_sesame.Watcher.FS.watch ~watcher ~engine "data")
  in
  Lwt_main.run
    (Lwt.choose
       [
         Current.Engine.thread engine;
         Lwt_result.ok
         @@ Lwt.bind f (fun (_, reload) ->
                (* Pass the condition variable into the development server *)
                Current_sesame.Server.dev_server ~port:8080 ~reload dst);
       ])

Images

Current_sesame.Image provides the OCurrent-powered forms of Sesame.Image

Server and Watcher

Current_sesame.Watcher and Current_sesame.Server together provide hot-reloading functionality thanks to web-sockets and irmin-watcher