This middleware in some sense like a builtin lack-middleware-static, reviewed last week.
The difference is that this middleware is more suitable for production because implements an infinite cache TTL for static assets.
An infinite cache TTL trick is useful when you want to speed up your website loading. Here is how it works.
Your server returns Cache-Control
HTTP header and set static files TTL to
some large value like a year to make it cached for a long long period of
time.
But how to expire this cache if you will need to update CSS or JavaScript on your site?
The only way is to change the URL. This is what lack-middleware-static
does for you. It calculates MD5 hash from the file’s content and makes
it a part of the URL.
When the content of the static file is changed, its URL changed as well. Browser notices that change and reloads the content.
Middleware provides a special tag for Djula template language. Setting
up templates for djula is out of thescope of this post and we’ll use
busted-uri-for-path
instead, to create a path to a file including a
cache hash.
First, we need to start our server and configure the middleware. Pay
attention to the probe-file
call. Root should be an absolute
pathname. With relative pathname, you’ll get a wrong result :(
POFTHEDAY> (clack:clackup
(funcall
clack-static-asset-middleware:*clack-static-asset-middleware*
(lambda (env)
(list 200 (list :content-type "text/plain")
(list (format nil
"Access this file: ~A"
(clack-static-asset-middleware:busted-uri-for-path
"site.css")))))
:path "static/"
:root (probe-file "static-files/"))
:port 9004)
Hunchentoot server is started.
Listening on 127.0.0.1:9004.
Now we can access our index page to get the static’s URL:
POFTHEDAY> (dex:get "http://localhost:9004/")
"Access this file: /static/site_ebb4fccbf8e0590b0fcf44c3748af88d.css"
200
Pay attention to the file’s suffix. It is an md5 hash from file’s content. This sum is calculated when you start the application. If you’ll change the file, during the next deploy another md5 hash will be generated and browser will reload its content.
If we’ll access this file, the server will respond with Cache-Control
header
and set the TTL to 1 year:
POFTHEDAY> (dex:get "http://localhost:9004/static/site_ebb4fccbf8e0590b0fcf44c3748af88d.css")
"body {font-size: 10px;}"
200 (8 bits, #xC8, #o310, #b11001000)
#<HASH-TABLE :TEST EQUAL :COUNT 8 {1001E58473}>
#<QURI.URI.HTTP:URI-HTTP http://localhost:9004/static/site_ebb4fccbf8e0590b0fcf44c3748af88d.css>
#<SB-SYS:FD-STREAM for "socket 127.0.0.1:53729, peer: 127.0.0.1:9004" {1001E37873}>
POFTHEDAY> (rutils:hash-table-to-alist #v56:2)
(("date" . "Tue, 30 Jun 2020 19:39:55 GMT")
("server" . "Hunchentoot 1.3.0")
("accept-ranges" . "bytes")
("last-modified" . "Tue, 30 Jun 2020 19:15:56 GMT")
("vary" . "Accept-Encoding")
("cache-control" . "public, max-age=31556926")
("content-length" . "23")
("content-type" . "text/css; charset=utf-8"))
Tomorrow we’ll review the last Clack’s middleware. I found only 3 of them on the Quicklisp. If you know about other middlewares, let me know and we’ll continue our journey to the world of web development with Clack!