0.0
The project is in a healthy, maintained state
Modern asset processing for Jekyll with image transformations
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 2.0
~> 3.0

Runtime

~> 1.11
>= 3.7, < 5.0
~> 3.0
 Project Readme

Jekyll-Skyhook ✈️

Modern asset processing for Jekyll with image transformations:

  • Image transformations - resize, format conversion (WebP, AVIF, etc.)
  • Responsive images - automatic srcset generation
  • Cache-busting digests - fingerprinted asset URLs
  • CSS url() rewriting - automatic asset path updates
  • Development file watcher - automatic regeneration
  • Manifest-based caching - avoid duplicate processing

Installation

  1. Add to your Gemfile:
group :jekyll_plugins do
  gem 'jekyll-skyhook'
end

And then run

bundle install
  1. Install image processing library:

For ImageMagick (default):

# Ubuntu/Debian:
sudo apt-get install imagemagick
# macOS:
brew install imagemagick

For libvips (faster alternative):

# Ubuntu/Debian:
sudo apt-get install libvips
# macOS:
brew install vips
  1. Add _digested directory to .gitignore

Configuration

Add to _config.yml:

skyhook:
  # Directories to process (default: ['assets'])
  asset_dirs: [assets, images]

  # When to digest assets (default: true)
  # Can be:
  #   - true (always digest)
  #   - false (never digest)
  #   - string (digest in specific environment)
  #   - array (digest in multiple environments)
  digest_assets: true
  # Examples:
  # digest_assets: true
  # digest_assets: false
  # digest_assets: production
  # digest_assets: [staging, production]

  # Directory for digested assets (default: '_digested')
  digest_dir: '_digested'

  # Image processing library (default: 'mini_magick')
  # Options: 'mini_magick' or 'vips'
  # vips is faster but requires libvips to be installed
  image_processor: mini_magick

# Include digested files in build
include:
  - _digested

Usage

Basic Asset Digesting

Use the {% asset %} tag for regular assets with cache-busting digests:

<link rel="stylesheet" href="{% asset assets/styles.css %}">
<script src="{% asset assets/app.js %}"></script>

Image Transformations

Use the {% image_transform %} tag with bracket syntax for image transformations:

<!-- Resize image -->
{% image_transform assets/hero.jpg[width="400"] %}

<!-- Convert format -->
{% image_transform assets/hero.jpg[format="webp"] %}

<!-- Multiple transformations -->
{% image_transform assets/hero.jpg[width="800"][format="avif"] %}

<!-- Use in img tag -->
<img src="{% image_transform assets/hero.jpg[width="400"][format="webp"] %}"
     alt="Hero image" loading="lazy">

Supported transformations:

  • width="400" - Resize to maximum width (maintains aspect ratio)
  • height="300" - Resize to maximum height (maintains aspect ratio)
  • format="webp" - Convert to WebP, AVIF, PNG, or JPEG

Responsive Images with Srcset

Use the {% srcset %} tag to generate responsive image sets:

<!-- Generate multiple sizes in original format -->
{% srcset assets/hero.jpg 400 800 1200 %}

<!-- Generate multiple sizes in specific format -->
{% srcset assets/hero.jpg[format="webp"] 400 800 1200 %}

Complete Picture Element Example

Create modern responsive images with multiple formats:

<picture>
  <!-- AVIF sources -->
  <source
    type="image/avif"
    {% srcset assets/hero.jpg[format="avif"] 400 800 1200 %}
    sizes="(max-width: 600px) 100vw, 50vw">

  <!-- WebP fallback -->
  <source
    type="image/webp"
    {% srcset assets/hero.jpg[format="webp"] 400 800 1200 %}
    sizes="(max-width: 600px) 100vw, 50vw">

  <!-- Original format fallback + lazy loading -->
  <img
    src="{% image_transform assets/hero.jpg[width="800"] %}"
    {% srcset assets/hero.jpg 400 800 1200 %}
    sizes="(max-width: 600px) 100vw, 50vw"
    alt="Description of the image"
    loading="lazy">
</picture>

Liquid Variables

You can use Liquid variables in transformations:

{% assign mobile_width = "400" %}
{% assign format = "webp" %}

<img src="{% image_transform {{ page.featured_image }}[width="{{ mobile_width }}"][format="{{ format }}"] %}">

Manual Image Processing

For build scripts or advanced use cases, you can manually store processed images:

require 'image_processing/mini_magick'

# Process image
processed = ImageProcessing::MiniMagick
  .source("assets/hero.jpg")
  .resize_to_limit(400, 400)
  .convert("webp")
  .call

# Store in Skyhook manifest
skyhook = Jekyll::Skyhook.instance(site)
skyhook.store_version("assets/hero.jpg", {format: "webp", width: "400"}, processed.path)

File Structure

your-site/
├── assets/
│   ├── hero.jpg          # Original image
│   ├── styles.css        # Original CSS
│   └── app.js           # Original JS
├── _digested/           # Generated (add to .gitignore)
│   └── assets/
│       ├── hero-width400-abc123.webp
│       ├── hero-width800-def456.webp
│       ├── styles-xyz789.css
│       └── app-uvw012.js
├── _site/               # Jekyll build output
│   └── _digested/       # Digested assets maintain structure
│       └── assets/
│           ├── hero-width400-abc123.webp
│           ├── styles-xyz789.css
│           └── app-uvw012.js
└── .jekyll-cache/
    └── skyhook/
        └── assets-manifest.json  # Tracks all transformations

How It Works

  1. Build time: Skyhook processes all assets in configured directories
  2. Transformations: Images are resized/converted to different formats
  3. Digests: Each transformation gets a unique hash based on content
  4. Manifest: All mappings stored in assets-manifest.json for fast lookups
  5. Static files: Transformed assets automatically added to Jekyll's static file list
  6. Development: File watcher regenerates assets when source files change

Performance

  • Caching: Identical transformations are cached and reused
  • Incremental: Only changed assets are reprocessed
  • Manifest: Fast lookups avoid redundant processing
  • Parallel: Multiple transformations can be processed concurrently

Troubleshooting

ImageMagick not found

# Install ImageMagick
brew install imagemagick  # macOS
sudo apt-get install imagemagick  # Ubuntu/Debian

Assets not found

  • Ensure asset directories exist in _config.yml
  • Check that _digested is included in Jekyll build
  • Verify file paths are correct (relative to site source)

Large build times

  • Limit asset directories to only what needs processing
  • Use digest_assets: false in development if needed
  • Consider pre-generating large image sets

Drafts not working

  • Ensure you're running Jekyll with --drafts flag when working on drafts
  • Assets are processed regardless of draft visibility
  • Both jekyll serve --drafts and jekyll build --drafts are supported