YOCaml

A development server

Now that we have some pages, let’s see how to set up a small development server to preview our generated site in action!

# #install_printer Yocaml.Path.pp ;;
# #install_printer Yocaml.Deps.pp ;;
open Yocaml
let www = Path.rel [ "_www" ] ;;

Up to now, we’ve been using cat each time to check that our generator was working properly. That wasn’t a very efficient approach—especially if we want to fine-tune our layout. Being able to view the site in a real environment is a huge advantage! You might think that since our generator produces HTML pages (among other things), we could simply open them directly in a web browser. Unfortunately, that doesn’t really work. When creating our templates, we assumed that the site would always be served from the root of a server—but chances are you’re not generating your site at the root of your computer’s filesystem, right?

To address this, the runtimes (Yocaml_unix and Yocaml_eio) come with a function similar to run, whose purpose is to start a small local server that serves our files:

Starting the Server

The function is very similar to its counterpart, run. Let’s take a quick look at its specification:

# Yocaml_unix.serve ;;
- : ?level:Yocaml_runtime.Log.level ->
    ?custom_error_handler:(Format.formatter ->
                           Yocaml.Data.Validation.custom_error -> unit) ->
    target:Path.t -> port:int -> (unit -> unit Eff.t) -> unit
= <fun>

The function is very similar. Just like run, it also takes a log level, and the function (unit -> unit Yocaml.Eff.t) is the same as the one accepted by run. In fact, the only differences are in target and port.

  • target is the directory that will serve as the root of our server. Here, we’ll set it to the _www directory.

  • port is the port our server will listen on. For this example, we’ll use 8000.

Serving our Site

In practice, we can simply adjust how we run our generator like this:

let () = 
-  Yocaml_unix.run ~level:`Debug program
+  Yocaml_unix.serve 
+       ~level:`Info 
+       ~target:www ~port:8000 
+       program

If you run your generator (dune exec bin/blog.exe), you should see the following message appear in your terminal:

[INFO]Launching server <http://localhost:8000>

And by visiting localhost:8000, you should be able to see your website! Excellent.

Server Features

The server is essentially a development server—it is not intended for production use. In fact, every time the server receives a request, it re-runs the program.

The fact that the program is re-executed on every page refresh might sound alarming. However, remember that YOCaml strives for minimalism: if nothing has changed, refreshing a page will result in no modifications at all.

Additionally, the server provides a minimal browser view (if the directory does not contain an index.html page) and allows serving a /404.html page as a substitute for 404 errors.

Conditional Execution

Our initial approach is a bit crude. Ideally, we want to control via CLI arguments whether we want to build our site (for example, to be invoked from CI) or serve it during the drafting process.

We can use a very simple approach, which is sufficient for the purposes of this tutorial:


let () =
  match Sys.argv.(1) with
  | "server" -> 
    Yocaml_unix.serve 
       ~level:`Info 
       ~target:www 
       ~port:8000 
       program
  | _ | (exception _) -> 
     Yocaml_unix.run 
       ~level:`Debug 
       program

Of course, it’s possible to drastically improve our CLI by using tools like Cmdliner to, for instance, make the port configurable. (You can find resources for command-line parsing on the official site.)

Conclusion

We’ve seen how to support a small development server, which is very useful during the drafting or design process. It has been designed to be easy to use and flexible enough to cover a wide range of scenarios.