Interactive Static Site Development for Common Lisp
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Colin Okay 4e00ade9cf updated hyperthings link 1 month ago
.gitignore added gitignore 5 months ago
LICENSE added license 5 months ago updated hyperthings link 1 month ago
flexo.asd filled out asd file 5 months ago
flexo.lisp changed the way add-files-matching works 2 months ago
package.lisp added *host* dynamic variable 5 months ago


alpha quality software

The Common Lisp, interactive system for static site generation.

For an example of a site made with flexo, see my site's source

The idea is this:

  1. You make a recipe that builds your site. It typically has two parts:
  • The recipe first adds and classifies content resources, which are usually files on disk
  • The recipie then uses those resources to build "artifacts", which are mostly pages.
  1. You then pass the recipie to a function that builds and publishes the site.

A Basic Example

;; A recipe. Makes a single page.
(defun my-site-recipe () 
  (page-with-main-layout "/index.html" 'index-page-content))

The above recipe is a function of zero arguments. It will be called by builder functions in a special context where a few dynamic variables are approrpiately assigned.

It should be noted that recipies can be nested: you can call one recipe inside another. If your site is large, you may benefit from developing portions of the site in their own recipes which are themselves composed in a single top-level recipe.

The page-with-main-layout is a template defined like so:

(define-spinneret-template page-with-main-layout
    (url content-view)
    (:meta :name "viewport" :content "width=device-width, initial-scale=1")
    (:div :class "main-layout"
          (funcall content-view)))))

Notice that the template is defined to accept a functional argument called content-view.
When we called page-with-main-layout in our recipe above, we passed index-page-content as the content-view argument. This is just a function that prints to the spinneret html stream.

(defun index-page-content ()
    (:h2 :class "center" "A Heading")
    (:p "Some text.")))

Right now, macros to define page templates are exclusively using spinneret, but there is no reason that other systems cannot be added.

You can then build the site to disk by doing:

   #P"/home/me/sites/my-site" ; where files end up
   "")     ; the host where this is intended to be served

But while you are developing a site, you're unlikely to use build-and-publish very much. Flexo is mainly for interactive development of static sites:

Interactive development

The real benefit of flexo is interactive development.

If you run the function

(hack-on 'my-site-recipe #P/tmp/flexo-hack-space/" :port 4242)

The you can do things like add new resources and recompile the functions that build artifact and the site will automatically redisplay.

Future development

  • Separate spinneret, LASS, and parenscript template macros into their own packages
  • Document the CLOS Protocol that Flexo uses, including how to extend it to:
    • Make your own artifact classes
    • Make your own content classes
    • Make your own publication location classes (only publishing to disk is presently supported)
  • Add content as:
    • Entire separate document trees for importing "subsites"
    • Database Queries as resources, not just files
    • API calls as resources, not just files