metalsmith-optimize-images 0.9.0 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # metalsmith-optimize-images
2
2
 
3
- > **🚀 Release Candidate**: This plugin has achieved comprehensive test coverage (96.06%) and is ready for production testing. Feedback welcome before 1.0.0 release!
3
+ > **🚀 Release Candidate**: This plugin has achieved comprehensive test coverage (95.27%) and is ready for production testing. Recent critical bug fixes have resolved recursive processing and AVIF format issues. Feedback welcome before 1.0.0 release!
4
4
 
5
5
  Metalsmith plugin for generating responsive images with optimal formats
6
6
 
@@ -15,12 +15,13 @@ Metalsmith plugin for generating responsive images with optimal formats
15
15
 
16
16
  - **Multiple image formats**: Generates AVIF and WebP variants with JPEG/PNG fallbacks
17
17
  - **Responsive sizes**: Creates different image sizes for various device widths
18
+ - **Background image support**: Automatically processes unused images for CSS `image-set()` backgrounds
18
19
  - **Progressive loading**: Optional progressive image loading with low-quality placeholders
19
20
  - **Lazy loading**: Uses native browser lazy loading for better performance
20
21
  - **Content-based hashing**: Adds hash to filenames for optimal caching
21
22
  - **Layout shift prevention**: Adds width/height attributes
22
23
  - **Parallel processing**: Processes images in parallel for faster builds
23
- - **Metadata generation**: Creates a JSON file with image information
24
+ - **Metadata generation**: Creates a JSON manifest with image information and variants
24
25
  - **Configurable compression**: Customize compression settings per format
25
26
  - **ESM and CommonJS support**:
26
27
  - ESM: `import optimizeImages from 'metalsmith-optimize-images'`
@@ -69,23 +70,24 @@ metalsmith
69
70
 
70
71
  ## Options
71
72
 
72
- | Option | Type | Default | Description |
73
- | --------------------- | ---------- | ------------------------------------- | ---------------------------------------- |
74
- | `widths` | `number[]` | `[320, 640, 960, 1280, 1920]` | Image sizes to generate |
75
- | `formats` | `string[]` | `['avif', 'webp', 'original']` | Image formats in order of preference |
76
- | `formatOptions` | `object` | See below | Format-specific compression settings |
77
- | `htmlPattern` | `string` | `**/*.html` | Glob pattern to match HTML files |
78
- | `imgSelector` | `string` | `img:not([data-no-responsive])` | CSS selector for images to process |
79
- | `outputDir` | `string` | `assets/images/responsive` | Where to store the responsive images |
80
- | `outputPattern` | `string` | `[filename]-[width]w-[hash].[format]` | Filename pattern with tokens |
81
- | `skipLarger` | `boolean` | `true` | Don't upscale images |
82
- | `lazy` | `boolean` | `true` | Use native lazy loading |
83
- | `dimensionAttributes` | `boolean` | `true` | Add width/height to prevent layout shift |
84
- | `sizes` | `string` | `(max-width: 768px) 100vw, 75vw` | Default sizes attribute |
85
- | `concurrency` | `number` | `5` | Process N images at a time |
86
- | `generateMetadata` | `boolean` | `false` | Generate a metadata JSON file |
87
- | `isProgressive` | `boolean` | `false` | Enable progressive image loading |
88
- | `placeholder` | `object` | See below | Placeholder image settings |
73
+ | Option | Type | Default | Description |
74
+ | --------------------- | ---------- | ------------------------------------- | ------------------------------------------------------------------------------ |
75
+ | `widths` | `number[]` | `[320, 640, 960, 1280, 1920]` | Image sizes to generate |
76
+ | `formats` | `string[]` | `['avif', 'webp', 'original']` | Image formats in order of preference |
77
+ | `formatOptions` | `object` | See below | Format-specific compression settings |
78
+ | `htmlPattern` | `string` | `**/*.html` | Glob pattern to match HTML files |
79
+ | `imgSelector` | `string` | `img:not([data-no-responsive])` | CSS selector for images to process |
80
+ | `outputDir` | `string` | `assets/images/responsive` | Where to store the responsive images |
81
+ | `outputPattern` | `string` | `[filename]-[width]w-[hash].[format]` | Filename pattern with tokens |
82
+ | `skipLarger` | `boolean` | `true` | Don't upscale images |
83
+ | `lazy` | `boolean` | `true` | Use native lazy loading |
84
+ | `dimensionAttributes` | `boolean` | `true` | Add width/height to prevent layout shift |
85
+ | `sizes` | `string` | `(max-width: 768px) 100vw, 75vw` | Default sizes attribute |
86
+ | `concurrency` | `number` | `5` | Process N images at a time |
87
+ | `generateMetadata` | `boolean` | `false` | Generate a metadata JSON file at `{outputDir}/responsive-images-manifest.json` |
88
+ | `isProgressive` | `boolean` | `false` | Enable progressive image loading |
89
+ | `placeholder` | `object` | See below | Placeholder image settings |
90
+ | `processUnusedImages` | `boolean` | `true` | Process unused images for background use |
89
91
 
90
92
  ### Default Format Options
91
93
 
@@ -112,7 +114,9 @@ metalsmith
112
114
 
113
115
  ### Standard Mode (default)
114
116
 
115
- The plugin:
117
+ The plugin operates in two phases:
118
+
119
+ **Phase 1: HTML-Referenced Images**
116
120
 
117
121
  1. Scans HTML files for image tags
118
122
  2. Processes each image to create multiple sizes and formats
@@ -121,6 +125,13 @@ The plugin:
121
125
  5. Adds width/height attributes to prevent layout shifts
122
126
  6. Implements native lazy loading for better performance
123
127
 
128
+ **Phase 2: Background Images (when `processUnusedImages: true`)**
129
+
130
+ 1. Finds images that weren't processed in Phase 1
131
+ 2. Generates 1x/2x variants (half size and original size) for retina displays
132
+ 3. Creates all configured formats (AVIF, WebP, original)
133
+ 4. Suitable for use with CSS `image-set()` for background images
134
+
124
135
  ### Progressive Mode (experimental)
125
136
 
126
137
  When `isProgressive: true` is enabled:
@@ -164,6 +175,9 @@ metalsmith.use(
164
175
  // Custom output directory
165
176
  outputDir: 'images/processed',
166
177
 
178
+ // Generate metadata manifest
179
+ generateMetadata: true, // Creates images/processed/responsive-images-manifest.json
180
+
167
181
  // Don't add lazy loading
168
182
  lazy: false
169
183
  })
@@ -199,6 +213,82 @@ Add the `data-no-responsive` attribute to any image you don't want processed:
199
213
  <img src="image.jpg" data-no-responsive alt="This image won't be processed" />
200
214
  ```
201
215
 
216
+ ## Background Images
217
+
218
+ The plugin automatically processes images that aren't referenced in HTML for use as CSS background images. This feature is enabled by default (`processUnusedImages: true`).
219
+
220
+ ### How Background Processing Works
221
+
222
+ After processing HTML-referenced images, the plugin:
223
+
224
+ 1. **Scans the Metalsmith files object** for all images
225
+ 2. **Excludes already-processed images** (those found during HTML scanning)
226
+ 3. **Excludes responsive variants** (generated images in the outputDir)
227
+ 4. **Generates 1x/2x variants** using actual image dimensions:
228
+ - **1x variant**: Half the original size for regular displays
229
+ - **2x variant**: Original image size for retina displays (sharper on high-DPI screens)
230
+ 5. **Creates all formats** (AVIF, WebP, original) for optimal browser support
231
+ 6. **No HTML replacement** - you manually write CSS with `image-set()`
232
+
233
+ ### Using Background Images with CSS
234
+
235
+ For an image like `images/hero.jpg` (1920x1080 pixels), the plugin generates variants like:
236
+
237
+ ```
238
+ assets/images/responsive/hero-960w.avif (1x - half 960px width for regular displays)
239
+ assets/images/responsive/hero-1920w.avif (2x - original 1920px width, sharper on retina)
240
+ assets/images/responsive/hero-960w.webp (1x - half 960px width for regular displays)
241
+ assets/images/responsive/hero-1920w.webp (2x - original 1920px width, sharper on retina)
242
+ assets/images/responsive/hero-960w.jpg (1x - half 960px width for regular displays)
243
+ assets/images/responsive/hero-1920w.jpg (2x - original 1920px width, sharper on retina)
244
+ ```
245
+
246
+ **Note**: Background images are generated **without hashes** for easier CSS authoring. HTML images still include hashes for cache-busting.
247
+
248
+ Use them in CSS with `image-set()`:
249
+
250
+ ```css
251
+ .hero {
252
+ background-image: image-set(
253
+ url('/assets/images/responsive/hero-960w.avif') 1x,
254
+ url('/assets/images/responsive/hero-1920w.avif') 2x,
255
+ url('/assets/images/responsive/hero-960w.webp') 1x,
256
+ url('/assets/images/responsive/hero-1920w.webp') 2x,
257
+ url('/assets/images/responsive/hero-960w.jpg') 1x,
258
+ url('/assets/images/responsive/hero-1920w.jpg') 2x
259
+ );
260
+ background-size: cover;
261
+ background-position: center;
262
+ }
263
+ ```
264
+
265
+ ### Background Image Configuration
266
+
267
+ ```javascript
268
+ metalsmith.use(
269
+ optimizeImages({
270
+ // Standard HTML image processing
271
+ widths: [320, 640, 960, 1280, 1920],
272
+ formats: ['avif', 'webp', 'original'],
273
+
274
+ // Background image processing
275
+ processUnusedImages: true, // Enable background processing
276
+
277
+ // Generate metadata to see all variants
278
+ generateMetadata: true
279
+ })
280
+ );
281
+ ```
282
+
283
+ ### Benefits of Background Image Processing
284
+
285
+ - **Automatic format optimization** - Browser selects best supported format
286
+ - **Retina display support** - 2x variants provide crisp images on high-DPI screens
287
+ - **Smart sizing** - Uses actual image dimensions instead of arbitrary widths
288
+ - **No manual work** - Plugin automatically finds and processes unused images in Metalsmith files object
289
+ - **Consistent workflow** - Same formats and quality settings as HTML images
290
+ - **Efficient processing** - Parallel processing of sizes and formats
291
+
202
292
  ## Progressive Loading
203
293
 
204
294
  ### Overview
@@ -295,6 +385,37 @@ The plugin provides CSS for progressive loading, but you can customize it:
295
385
  }
296
386
  ```
297
387
 
388
+ ## Metadata Manifest
389
+
390
+ When `generateMetadata: true` is enabled, the plugin creates a JSON file at `{outputDir}/responsive-images-manifest.json` containing detailed information about all processed images:
391
+
392
+ ```json
393
+ {
394
+ "images/hero.jpg": [
395
+ {
396
+ "path": "assets/images/responsive/hero-320w-a1b2c3d4.avif",
397
+ "width": 320,
398
+ "height": 180,
399
+ "format": "avif",
400
+ "size": 8432
401
+ },
402
+ {
403
+ "path": "assets/images/responsive/hero-320w-a1b2c3d4.webp",
404
+ "width": 320,
405
+ "height": 180,
406
+ "format": "webp",
407
+ "size": 12658
408
+ }
409
+ ]
410
+ }
411
+ ```
412
+
413
+ This manifest is useful for:
414
+
415
+ - **Debugging**: Verify which variants were generated
416
+ - **Integration**: Use variant information in other tools
417
+ - **Performance analysis**: Compare file sizes across formats
418
+
298
419
  ## Debug
299
420
 
300
421
  To enable debug logs, set the DEBUG environment variable to metalsmith-optimize-images\*:
@@ -318,6 +439,14 @@ metalsmith.env('DEBUG', 'metalsmith-optimize-images*');
318
439
  }
319
440
  ```
320
441
 
442
+ ## Recent Updates
443
+
444
+ ### Bug Fixes (January 2025)
445
+
446
+ - **🚫 Fixed Recursive Processing**: Resolved critical issue where the background image processor was finding already-generated responsive images and reprocessing them recursively, creating malformed filenames like `image-320w-640w-960w.jpg`
447
+ - **🚫 Fixed HEIF Extension Issue**: Fixed Sharp.js AVIF processing that was sometimes generating `.heif` extensions instead of `.avif`
448
+ - **✅ Enhanced Background Image Filtering**: Added comprehensive filtering to prevent responsive variants from being treated as source images
449
+
321
450
  ## Feedback & Testing
322
451
 
323
452
  This plugin is approaching 1.0.0 and we'd love your feedback! Please test and report:
@@ -329,10 +458,11 @@ This plugin is approaching 1.0.0 and we'd love your feedback! Please test and re
329
458
  - **Memory usage**: Resource consumption in your environment
330
459
  - **Cross-platform consistency**: Image quality and file sizes across platforms
331
460
  - **Progressive loading**: Behavior across different browsers
461
+ - **Background image processing**: Testing the new `image-set()` feature with CSS backgrounds
332
462
 
333
463
  ### Current Status
334
464
 
335
- - ✅ 96.06% test coverage with comprehensive edge case handling
465
+ - ✅ 95.27% test coverage with comprehensive edge case handling
336
466
  - ✅ Real Metalsmith integration tests (no mocks)
337
467
  - ✅ Tested on macOS with Node.js 18+
338
468
  - 🔄 Seeking broader platform validation
@@ -349,6 +479,6 @@ MIT
349
479
  [metalsmith-url]: https://metalsmith.io
350
480
  [license-badge]: https://img.shields.io/github/license/wernerglinka/metalsmith-optimize-images
351
481
  [license-url]: LICENSE
352
- [coverage-badge]: https://img.shields.io/badge/test%20coverage-96%25-brightgreen
482
+ [coverage-badge]: https://img.shields.io/badge/test%20coverage-95%25-brightgreen
353
483
  [coverage-url]: https://github.com/wernerglinka/metalsmith-optimize-images/actions/workflows/test.yml
354
484
  [modules-badge]: https://img.shields.io/badge/modules-ESM%2FCJS-blue