@adaptive-ds/assets-optimizer
v0.6.0
Published
Process and sync web project images and videos between local folders and R2
Downloads
1,084
Maintainers
Readme
@adaptive-ds/assets-optimizer
Process, hash, sync, and clean image assets for web projects that keep originals outside git and optionally sync through any rclone remote, with a separate pass for web videos.
Features
- originals may live on an
rcloneremote and be synced locally - optimized outputs should be deterministic and aggressively cacheable
- output filenames should change when either the source file or the transform changes
- old optimized files should be removed locally and remotely
- generates type-safe
imageList.tsandvideoList.tsshould stay in sync with processed assets
Quick link
- code - https://github.com/david1gp/assets-optimizer
- npm - https://www.npmjs.com/package/@adaptive-ds/assets-optimizer
Diagrams
Overview
Images
Videos
What It Does
processAssets() orchestrates the full workflow:
- Syncs originals from remote source to local
imagesandvideosfolders viarclone bisync - Runs
assetsOptimize()to process images and videos locally - Uploads optimized assets to s3-compatible remote destination with caching headers
assetsOptimize() performs the core asset processing:
- Resolves the project name from
package.json.name - If
rcloneRemoteis configured, uses that project name as the base path on the remote - If
rcloneRemoteis configured, syncs originals between the remote andimages - Scans transform folders like
1920x1080_jpg - Processes matching image source files with
sharp - Writes flat optimized images into
public/images - Names image files as
<basename>_<hash>.<ext> - Skips already-generated images
- Deletes stale optimized images locally
- If
rcloneRemoteis configured, uploads missing optimized images to the remote with cache headers - If
rcloneRemoteis configured, deletes stale optimized images from the remote - Runs a separate optional video pass from
videostopublic/videos - Generates a
.jpgpreview beside each processed video using the processed video dimensions - Keeps video filenames unchanged and skips any processed video or preview that already exists
- If
rcloneRemoteis configured, uploads missing processed videos and previews to the remote without deleting manual variants - Generates
src/app/assets/imageList.tsandsrc/app/assets/videoList.tsby default - Prints a clear summary of what changed
The hash is derived from:
- source file bytes
- normalized transform spec
That means image cache keys change when the source image changes or when you change the folder rule, even if the output filename format stays short.
Folder Convention
Original files belong in transform folders inside images.
Example:
images/
1920x1080_jpg/
living-room.png
1200x1200_webp/
kitchen.jpgThis produces flat optimized image output like:
public/images/
kitchen_a1b2c3d4.jpg
living-room_9f8e7d6c.jpg
kitchen_7c6b5a4d.webpRoot-level files directly inside images are intentionally skipped and warned on every run.
Videos are handled separately and do not use transform folders:
videos/
hero.mp4
intro.webm
public/videos/
hero.mp4
hero.jpg
intro.webm
intro.jpgVideo behavior:
- if both local
videosand remotevideo-originalsare missing, the video pass does nothing - if
rcloneRemoteis configured, source videos sync throughvideo-originals - if
rcloneRemoteis configured, processed videos sync throughvideo-processed - missing processed videos are created with
ffmpeg - missing preview images are created as
.jpgfiles beside processed videos - existing processed videos are skipped and preserved as manual transformations
- existing preview images are skipped and preserved
- video filenames and relative paths are kept as-is
- stale processed videos are not deleted
Transform Folder Format
Folder names must use:
<width>x<height>_<format>Supported image output formats:
jpgpngwebpExamples:1920x1080_jpg1600x900_webpImage processing behavior:resize fit:
inside/ max-bounds scalingwithoutEnlargement: trueimage auto-rotation is applied
default quality is
80
Supported video source extensions:
mp4movm4vwebmavimkv
Installation
bun add -D @adaptive-ds/assets-optimizerBasic Usage
Example project entrypoint:
import { assetsProcess } from "@adaptive-ds/assets-optimizer"
await assetsProcess()This generates optimized images, processed videos, video preview JPGs, imageList.ts, and videoList.ts in one run.
Existing image alt text and existing video preview alt text are preserved when the generated files already exist.
Local folders
This package is built for a workflow with two local directories:
images: original source images, never modifiedpublic/images: generated optimized images, flat output onlyvideos: original source videos, optionalpublic/videos: processed videos, optional
Optimization
Images
- Source images live in transform folders like
1920x1080_jpginsideimages/ - Each source file is resized to fit within the specified bounds without enlargement
- Auto-rotation is applied based on EXIF data
- Output quality defaults to 80%
- Files are named using a hash of the source content and transform spec
- Existing optimized files are skipped unless their source changed
- Stale optimized files (from deleted sources or changed transforms) are removed
- A TypeScript list file is generated with all processed image references
Videos
- Source videos live directly in
videos/(no transform folders) - Each video is copied to the output directory using
ffmpeg - A JPEG preview is generated beside each processed video
- Existing processed videos and previews are preserved as-is
- A TypeScript list file is generated with all processed video references
Requirements
bunrcloneffmpeg- an existing
rcloneremote - write access to the target bucket/path
- Node/Bun environment capable of running
sharp
This package assumes the remote bucket/path already exists or can be created by rclone mkdir.
Cleanup Behavior
The package does not use a manifest.
Instead it derives the expected output set from the current originals and current transform folders, then reconciles that against:
- local
public/images - remote
images/optimizedobjects
That means:
- files no longer produced by the current source set are deleted
- renaming or removing a source file cleans up stale optimized files
- changing a transform folder causes a different hash and a different output filename
Recommended Workflow
- Add or sync originals into
images/<transform-folder>/ - Run your local image pipeline entrypoint
- Regenerate your typed image list
- Reference the generated hashed filenames from app code or derived metadata
Important Caveat
If your project currently stores source images directly at the root of images, this package will skip them by design.
Before adopting it fully, move originals into explicit transform folders such as:
images/1920x1080_jpg/That contract is what makes the output deterministic and safe to clean automatically.
License
MIT
