To provide a lack middleware for compressing and caching static resources like css and javasrcipt.
As of today 2024/09/25 this is not in quicklisp. You can just download the source code from here and load it with quicklisp or asdf after you set the directory where you save it to be in the registry.
This project depends on https://github.com/daninus14/compression-cache also not in quicklisp. You can download the code straight from the source.
- We are currently using gzip compression. The code is made extensible, so adding a different type of compression should be trivial, however, the change must be made in compression-cache and lack-compression-cache.
- The middleware should be able to be added like any other lack middleware.
- See https://github.com/fukamachi/lack for an explanation
- There are some precompressed files that will not be compressed. See below for a full list.
- We are setting HTTP Cache Headers
- We are setting the
Cache-Control
HTTP header as follows"max-age=31536000, immutable"
. - We are setting the
Expires
HTTP header for a full year into the future. - We added an option to disable these headers with
:no-http-cache T
.
- We are setting the
The middleware API looks like the following
(:compression-cache :cache-path "bin/cache" :static-files-path "/static/" :no-http-cache T)
Or
(lambda (app &key cache-path static-files-path (root #P"./") (no-http-cache NIL)))
- Please note that you should have some files in the
static
directory mentioned in the examples below, preferrably large css or javascript files. - Then confirm in your network tab in the browser that the file size loaded is much smaller than whatever appears in the filesystem locally.
- You can check also that inside the
bin/cache
directory a new compressed version of that file was saved.
See the `example.lisp`
(ql:quickload "clack")
(defvar *app*
(lambda (env)
(declare (ignorable env))
'(200 (:content-type "text/plain") ("Hello, Compression2!"))))
(defvar *compressed-app*
(funcall lack/middleware/compression-cache:*lack-middleware-compression-cache*
*app* :cache-path "bin/cache" :static-files-path "static/"))
(defvar *clack-handler*
(clack:clackup *compressed-app*))
;; To Stop the App
(clack:stop *clack-handler*)
(ql:quickload "clack")
(ql:quickload "lack")
(defvar *app*
(lambda (env)
(declare (ignorable env))
'(200 (:content-type "text/plain") ("Hello, Compression2!"))))
(defvar *compressed-app*
(lack:builder
(:compression-cache :cache-path "bin/cache" :static-files-path "static/")
(:static :path "/public/"
:root #P"/static-files/")
*app*))
(defvar *clack-handler*
(clack:clackup *compressed-app*))
;; To Stop the App
(clack:stop *clack-handler*)
The following file formats are usually compressed already, so they will not be compressed.
Image formats: JPEG PNG GIF WebP
Audio formats: MP3 AAC FLAC OGG
Video formats: MP4 AVI MOV WebM
Archive formats: ZIP RAR TAR 7z
PDF Files are sometimes compressed. There is a way to check if the file is compressed by opening it.
We could implement this in common lisp in the future for figuring out if a PDF should be compressed.
import PyPDF2
def is_pdf_compressed(pdf_path):
"""Checks if a PDF file is compressed using PyPDF2.
Args:
pdf_path (str): The path to the PDF file.
Returns:
bool: True if the PDF is compressed, False otherwise.
"""
with open(pdf_path, 'rb') as pdf_file:
reader = PyPDF2.PdfReader(pdf_file)
for page in reader.pages:
if page.mediabox.width != page.cropbox.width or page.mediabox.height != page.cropbox.height:
return True # Indicates potential compression
for obj in page.resources.get('/XObject', {}):
stream = page.resources.get('/XObject')[obj]
if stream.get('/Filter') == '/FlateDecode':
return True # Explicitly checks for FlateDecode filter
return False
# Example usage:
pdf_path = "your_pdf_file.pdf"
if is_pdf_compressed(pdf_path):
print("The PDF file is compressed.")
else:
print("The PDF file is not compressed.")