Clojure Stack TemplatesClojure Stack Templates

Frontend

UI development

POST requests

The server includes wrap-anti-forgery middleware by default to protect your application from CSRF attacks. This security measure requires all POST requests to include a CSRF token in the request body. You can include a CSRF token in two ways:

  1. Hidden input field in the form:
src/myproject/views.clj
(ns myproject.views
  (:require ;...
            [reitit-extras.core :as reitit-extras]))
 
[:form
  (reitit-extras/csrf-token-html)
  ;...
  ]
  1. Header in the request:
src/myproject/views.clj
; ...
[:button
 {:hx-delete "/api/delete"
  :hx-headers (reitit-extras/csrf-token-json)}
 "Delete"]

Tailwind CSS setup

For CSS styling, Clojure Stack Lite uses Tailwind CSS with the simplest installation method via the CLI tool:

mise install tailwindcss

The minimal configuration is in the resources/public/css/input.css file where you can add your own customizations:

resources/public/css/input.css
@import 'tailwindcss' source("../../../src");

This configuration detects all changes in the src folder and automatically rebuilds the CSS file.

There are two commands available for working with Tailwind CSS:

  1. bb css-watch - watches for changes in CSS files and recompiles them in real-time (for development)
  2. bb css-build - builds CSS files once (for production)

By default, the application system uses bb css-watch to compile CSS files. Both commands generate a resources/public/css/output.css file with compiled CSS. You can add or modify any CSS class in Hiccup in any project file, and after refreshing the page, you'll immediately see the changes in the browser.

The bb css-watch command starts automatically only in development mode:

resources/config.dev.edn
#merge [#include "config.edn"
        {:integrant-extras.process/process {:cmd ["bb" "css-watch"]
                                            :opts {:err :inherit}}}]

This runs the bb css-watch command in the background. By default, you'll only see output about the first run. If you want to see complete output for each rebuild, you can add :opts {:err :inherit} to the process config:

resources/config.dev.edn
#merge [#include "config.edn"
        {:integrant-extras.process/process {:cmd ["bb" "css-watch"]
                                            :opts {:err :inherit}}}]

If you prefer not to start the bb css-watch command automatically with the dev system, you can remove the dev config file parameter from the read-config function:

dev/user.clj
;...
(defn reset
  "Restart system."
  []
  (ig-repl/set-prep! #(ig-extras/read-config :dev))
  (ig-repl/reset))
;...

Then you can run bb css-watch manually in your terminal.

Static assets management

The template implements a lightweight static assets management approach. The core concept is to vendor all assets in the resources/public folder except the output CSS file.

Fetching assets

By default, two JavaScript libraries are included in the template: resources/public/alpine.min.js and resources/public/htmx.min.js. Their versions are specified in the bb.edn file under the fetch-assets command:

{:tasks
 {;...
  fetch-assets {:doc "Fetch static file assets from URLs"
                :requires ([manifest-edn.core :as manifest])
                :task (manifest/fetch-assets!
                        [{:url "https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js"
                          :filepath "js/htmx.min.js"}
                         {:url "https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js"
                          :filepath "js/alpinejs.min.js"}])}

The lightweight manifest-edn library is used to fetch assets from URLs and save them in the resources/public folder according to the specified :filepath. You can easily add your own assets to the resources/public folder. For example, to add the response-targets extension for HTMX:

{:tasks
 {;...
  fetch-assets {;...
                :task (manifest/fetch-assets!
                        [;...
                         {:url "https://unpkg.com/htmx-ext-response-targets@2.0.2"
                          :filepath "js/htmx-ext-response-targets.min.js"}])}

After running bb fetch-assets, a new JS file resources/public/js/htmx-ext-response-targets.min.js will be added to your project.

Use assets in HTML

To use any asset in your HTML, simply wrap it with the asset function:

src/myproject/views.clj
(ns myproject.views
  (:require ;...
            [manifest-edn.core :as manifest]))
 
(defn base
  "Base component for html page."
  [content]
  [:html
   [:head
    [:link {:rel "icon"
            :href (manifest/asset "images/icon.svg")
            :type "image/svg+xml"}]
    [:link {:type "text/css"
            :href (manifest/asset "css/output.css")
            :rel "stylesheet"}]]
   [:body
    ;...
    [:script {:type "text/javascript"
              :src (manifest/asset "js/htmx.min.js")
              :defer true}]
    [:script {:type "text/javascript"
              :src (manifest/asset "js/htmx-ext-response-targets.min.js")
              :defer true}]
    [:script {:type "text/javascript"
              :src (manifest/asset "js/alpinejs.min.js")
              :defer true}]]])

This approach applies to all assets in the resources/public folder. For example, the image images/icon.svg is also wrapped with the asset function. In development, this function adds the prefix /assets to the path, making it available at http://localhost:3000/assets/images/icon.svg. In production, before building the jar file, (manifest/hash-assets!) runs to hash all assets from the public directory and add a manifest.edn file with all assets and their hashes. The manifest/asset function uses this hash to generate the path to the asset, enabling efficient caching and versioning.

PWA support

The template includes basic Progressive Web Application (PWA) support. It provides a manifest file but does not include a service worker by default. You can add your own service worker if needed for your application requirements.

The manifest file is located at resources/public/manifest.json and defines the PWA properties. By default, there's an optimized set of icons for the PWA, following the recommendations from this excellent favicon guide.

Important

Before deploying to production, remember to update the name, URL, and ID of the app in the resources/public/manifest.json file. You'll also likely want to replace the default icons in resources/public/images with your own branded assets.

On this page