Skip to content

lack middleware for compressing and caching static resources

License

Notifications You must be signed in to change notification settings

daninus14/lack-compression-cache

Repository files navigation

Motivation

To provide a lack middleware for compressing and caching static resources like css and javasrcipt.

Installation

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.

Dependencies

This project depends on https://github.com/daninus14/compression-cache also not in quicklisp. You can download the code straight from the source.

Usage

Usage Notes

  • 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.
  • 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.

API

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)))

Examples

  • 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.

Simple Example

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*)

Example with Lack Builder Sytnax

(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*)

Files That Will Not Be Compressed

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.

From a LLM for checking if PDFs are compressed:

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.")

About

lack middleware for compressing and caching static resources

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published