imagepreparation-lazy-srcset
v0.1.0
Published
Automatically prepare fotos for lazy-srcset npm plugin
Downloads
181
Maintainers
Readme
imagepreparation-lazy-srcset
This package was created specifically to prepare photos for use with the lazy-srcset package.
A Node.js library + CLI that prepares a folder of source photos for the lazy-srcset frontend lazy-loading pattern.
It resizes every image down to a set of responsive breakpoints, re-encodes each one to a modern format (webp by default), and stores everything in a content-addressable store so identical work is never redone. Each photo is content-hashed, organized into its own hash-named folder, and (optionally) "published" into the exact filename convention lazy-srcset expects on the frontend.
Features
- Responsive breakpoints — resizes each source image to multiple widths (default:
1920, 1440, 1280, 1024, 768, 640, 480, 320) without ever upscaling. - Modern formats — re-encodes to
webp(or any formatsharpsupports) at a configurable quality. - Content-addressable storage — resized variants are stored by content hash; running the tool again never duplicates work or storage.
- Content-based deduplication — two uploaded photos with identical bytes (even under different filenames) collapse into a single processed entry.
- Resumable manifest — a single
.img-manifest.jsonper collection tracks what's already been processed, so interrupted or repeated runs pick up where they left off. - Originals are preserved, not deleted — each source photo is kept (renamed) next to its generated variants, so future re-encodes (different quality/format/breakpoints) don't need the original upload again.
lazy-srcset-ready output — an explicit publish step links generated variants into the exactname-{width}.{ext}sibling-file convention the frontend package expects.
Installation
npm install imagepreparation-lazy-srcsetThis installs the image-preparation CLI binary. sharp is the only runtime dependency.
CLI usage
image-preparation <imagesDir> [options]or, without installing the bin globally:
node bin/cli.js <imagesDir> [options]| Argument / Flag | Default | Description |
| - | - | - |
| imagesDir (positional) | ./img | Folder containing the source photos (or path to a single image file). |
| --format | webp | Output format passed to sharp (e.g. webp, avif). |
| --quality | 82 | Encoding quality for the output format. |
| --breakpoints | 1920,1440,1280,1024,768,640,480,320 | Comma-separated list of target widths, in pixels. |
| --publish | off | After processing, link the generated variants into the lazy-srcset naming convention (see below). |
Example
image-preparation ./img --format webp --quality 80 --breakpoints 1600,1200,800,400 --publishHow it works
Discovery —
<imagesDir>is scanned for source images. Loose image files directly inside it, and one level of subfolders, are picked up as input. Already-known bucket folders (see below) and_-prefixed folders are skipped, so the tool's own output is never mistaken for new source material on the next run.Content hashing — each source file's content is SHA-1 hashed. That hash becomes both the photo's manifest key and its working folder name:
<imagesDir>/<hash>/. Because the hash is based on content, uploading the same photo twice under different names always resolves to the same folder.Resize + encode — for every configured breakpoint, the image is resized (
withoutEnlargement: true, so small originals are never blown up) and re-encoded to the target format/quality. If a resize produces byte-identical output to the previous (larger) breakpoint — common once the source is smaller than a given width — the existing variant is reused instead of storing a duplicate.Content-addressable store (CAS) — every resized variant is saved into
<hash>/.store/<h0:2>/<h2:4>/<variantHash>.<format>, keyed by its own content hash. A variant already on disk is never rewritten.Original preserved — the source file is moved (not deleted) into its bucket folder as
<hash>.<originalExt>, so it survives for future re-processing (e.g. with different quality/format/breakpoints).Manifest — a single
<imagesDir>/.img-manifest.jsonrecords, per photo hash, the{ width: variantHash }map. This is the durable record that makes re-runs skip already-processed photos.Publish (
--publish) — hard-links (falling back to a copy across filesystems) every CAS-stored variant out to<hash>/<hash>-<width>.<format>, right next to the preserved original. Already-correct links are left untouched, so publishing again after adding one new photo only touches that photo's folder.
Output layout
After processing and publishing a single photo, its folder looks like this:
img/
└── 2c905c69d5921635fcb59f8176c508c3ff806f4b/
├── .store/ # content-addressable, internal
│ └── 84/27/84279ca394ec...webp
├── 2c905c69d5921635fcb59f8176c508c3ff806f4b.jpg # preserved original
├── 2c905c69d5921635fcb59f8176c508c3ff806f4b-320.webp
├── 2c905c69d5921635fcb59f8176c508c3ff806f4b-480.webp
├── 2c905c69d5921635fcb59f8176c508c3ff806f4b-640.webp
├── 2c905c69d5921635fcb59f8176c508c3ff806f4b-768.webp
├── 2c905c69d5921635fcb59f8176c508c3ff806f4b-1024.webp
├── 2c905c69d5921635fcb59f8176c508c3ff806f4b-1280.webp
├── 2c905c69d5921635fcb59f8176c508c3ff806f4b-1440.webp
└── 2c905c69d5921635fcb59f8176c508c3ff806f4b-1920.webpUsing the output with lazy-srcset
lazy-srcset builds its srcset by appending -{width}.{ext} directly to whatever path is in an image's data-srcset attribute — it has no awareness of this tool's internal hashing. Point data-srcset at the published path for that photo's hash:
<img
class="lazy-srcset"
alt=""
src="data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 9"%3E%3C/svg%3E"
data-srcset="img/2c905c69d5921635fcb59f8176c508c3ff806f4b/2c905c69d5921635fcb59f8176c508c3ff806f4b.webp"
/>lazy-srcset will then resolve …-320.webp, …-480.webp, … …-1920.webp automatically. The hash for a given source photo can be looked up from .img-manifest.json (it's the top-level key).
Programmatic API
import { imagePipeline } from 'imagepreparation-lazy-srcset';
await imagePipeline({
imagesCollectionDir: './img', // folder or single file path
format: 'webp',
quality: 82,
breakpoints: [1920, 1440, 1280, 1024, 768, 640, 480, 320],
inputFormats: ['jpg', 'jpeg', 'png', 'webp', 'avif'],
publish: true,
});All options are optional and merge over the defaults shown above.
Status
This is an early, actively-evolving package — there is no test suite, lint config, or type checker yet. Planned next steps include manifest versioning, a garbage collector for orphaned .store entries, and incremental rebuilds that skip files whose settings haven't changed.
License
MIT
