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:
djula:*current-store*
as an instance of memory-template-store
,
setf djula:*recompile-templates-on-change* nil)
.
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.