npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

imagepreparation-lazy-srcset

v0.1.0

Published

Automatically prepare fotos for lazy-srcset npm plugin

Downloads

181

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 format sharp supports) 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.json per 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 exact name-{width}.{ext} sibling-file convention the frontend package expects.

Installation

npm install imagepreparation-lazy-srcset

This 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 --publish

How it works

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

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

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

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

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

  6. Manifest — a single <imagesDir>/.img-manifest.json records, per photo hash, the { width: variantHash } map. This is the durable record that makes re-runs skip already-processed photos.

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

Using 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