11 Deployment - Building standalone binaries

By default, when asked to compile a template, Djula searches the file system, in the directories you told it to look into. When you render a template that extends or includes another one, Djula searches for that one too. Moreover, Djula will try to re-compile a template at each access, whenever you reload a web page. This is very convenient for development, it doesn’t bother us to deploy our application from sources (although you may want to disable auto-reloading), but it prevents us from building a standalone binary that will run on another machine, when the search path’s directories don’t exist anymore.

To build a standalone binary, we will need to:

Below is a simple ASDF system declaration that declares two templates as static files located in the “src/templates” directory:

(asdf:defsystem "djula-binary"
  :depends-on (:hunchentoot
               :djula)
  :components ((:module "src"
                        :components
                        ((:file "web")))
               (:module "src/templates"
                        :components
                        ;; Order is important: the ones that extend base.html
                        ;; must be declared after it, because we compile all of them
                        ;; at build time one after the other.
                        ((:static-file "base.html")
                         (:static-file "search.html")))
               (:static-file "README.md"))

  :build-operation "program-op"
  :build-pathname "djula-binary"
  :entry-point "djula-binary::main"

  :description "How to embed Djula templates in a self-contained binary.")

At the top level of “src/web.lisp”, we set Djula’s store to a memory store, and we disable the autoreload feature. This code would be called when we load the .lisp file, so it will be called when we create the binary with (asdf:make :djula-binary).

(setf djula:*current-store* (make-instance 'djula:memory-template-store
					   :search-path (list (asdf:system-relative-pathname "djula-binary"
                                                             "src/templates/"))) ;; meaningful trailing /
      djula:*recompile-templates-on-change* nil)

Now, we compile all those declared templates. We use the djula:list-asdf-system-templates utility that will return a list of pathnames to our templates.

(mapcar #'djula:compile-template* (djula:list-asdf-system-templates :demo-djula-in-binaries "src/templates"))

Finally, you can declare templates as usual in your application:

(defparameter +base.html+ (djula:compile-template* "base.html"))

and render a template that extends another one, it will work (and that was actually the main difficulty: the default store always looks for this inherited template on the filesystem).

You can now send to your web server your self-contained, one file binary that you built on your machine or on a CI server.

Note: For a real-world web application you’ll likely need Deploy to ship foreign libraries in your binary.