metalsmith-optimize-images 0.9.0 → 0.10.0
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 +150 -57
- package/lib/index.cjs +399 -34
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +397 -32
- package/lib/index.js.map +1 -1
- package/package.json +10 -7
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
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!
|
|
4
|
-
|
|
5
3
|
Metalsmith plugin for generating responsive images with optimal formats
|
|
6
4
|
|
|
7
5
|
[![metalsmith:plugin][metalsmith-badge]][metalsmith-url]
|
|
@@ -11,16 +9,19 @@ Metalsmith plugin for generating responsive images with optimal formats
|
|
|
11
9
|
[![ESM/CommonJS][modules-badge]][npm-url]
|
|
12
10
|
[](https://snyk.io/test/npm/metalsmith-optimize-images)
|
|
13
11
|
|
|
12
|
+
> This Metalsmith plugin is under active development. The API is stable, but breaking changes may occur before reaching 1.0.0.
|
|
13
|
+
|
|
14
14
|
## Features
|
|
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
|
-
- **Lazy loading**: Uses native browser lazy loading
|
|
20
|
+
- **Lazy loading**: Uses native browser lazy loading
|
|
20
21
|
- **Content-based hashing**: Adds hash to filenames for optimal caching
|
|
21
22
|
- **Layout shift prevention**: Adds width/height attributes
|
|
22
|
-
- **Parallel processing**: Processes images in parallel
|
|
23
|
-
- **Metadata generation**: Creates a JSON
|
|
23
|
+
- **Parallel processing**: Processes images in parallel
|
|
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'`
|
|
@@ -32,20 +33,6 @@ Metalsmith plugin for generating responsive images with optimal formats
|
|
|
32
33
|
npm install metalsmith-optimize-images
|
|
33
34
|
```
|
|
34
35
|
|
|
35
|
-
## Requirements
|
|
36
|
-
|
|
37
|
-
- Node.js >=18.0.0
|
|
38
|
-
- Metalsmith >=2.5.0
|
|
39
|
-
|
|
40
|
-
## Platform Testing Status
|
|
41
|
-
|
|
42
|
-
- ✅ **macOS**: Fully tested and working
|
|
43
|
-
- 🔄 **Windows**: Seeking community feedback on Sharp.js compatibility
|
|
44
|
-
- 🔄 **Linux**: Seeking validation across different distributions
|
|
45
|
-
- 🔄 **CI/CD**: Testing in various containerized environments
|
|
46
|
-
|
|
47
|
-
**Help us reach 1.0.0**: If you test this plugin on Windows, Linux, or in production environments, please [share your experience](https://github.com/wernerglinka/metalsmith-optimize-images/issues)!
|
|
48
|
-
|
|
49
36
|
## Usage
|
|
50
37
|
|
|
51
38
|
> This plugin **must** be run after assets are copied but before any final HTML processing.
|
|
@@ -69,23 +56,24 @@ metalsmith
|
|
|
69
56
|
|
|
70
57
|
## Options
|
|
71
58
|
|
|
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
|
|
59
|
+
| Option | Type | Default | Description |
|
|
60
|
+
| --------------------- | ---------- | ------------------------------------- | ------------------------------------------------------------------------------ |
|
|
61
|
+
| `widths` | `number[]` | `[320, 640, 960, 1280, 1920]` | Image sizes to generate |
|
|
62
|
+
| `formats` | `string[]` | `['avif', 'webp', 'original']` | Image formats in order of preference |
|
|
63
|
+
| `formatOptions` | `object` | See below | Format-specific compression settings |
|
|
64
|
+
| `htmlPattern` | `string` | `**/*.html` | Glob pattern to match HTML files |
|
|
65
|
+
| `imgSelector` | `string` | `img:not([data-no-responsive])` | CSS selector for images to process |
|
|
66
|
+
| `outputDir` | `string` | `assets/images/responsive` | Where to store the responsive images |
|
|
67
|
+
| `outputPattern` | `string` | `[filename]-[width]w-[hash].[format]` | Filename pattern with tokens |
|
|
68
|
+
| `skipLarger` | `boolean` | `true` | Don't upscale images |
|
|
69
|
+
| `lazy` | `boolean` | `true` | Use native lazy loading |
|
|
70
|
+
| `dimensionAttributes` | `boolean` | `true` | Add width/height to prevent layout shift |
|
|
71
|
+
| `sizes` | `string` | `(max-width: 768px) 100vw, 75vw` | Default sizes attribute |
|
|
72
|
+
| `concurrency` | `number` | `5` | Process N images at a time |
|
|
73
|
+
| `generateMetadata` | `boolean` | `false` | Generate a metadata JSON file at `{outputDir}/responsive-images-manifest.json` |
|
|
74
|
+
| `isProgressive` | `boolean` | `false` | Enable progressive image loading |
|
|
75
|
+
| `placeholder` | `object` | See below | Placeholder image settings |
|
|
76
|
+
| `processUnusedImages` | `boolean` | `true` | Process unused images for background use |
|
|
89
77
|
|
|
90
78
|
### Default Format Options
|
|
91
79
|
|
|
@@ -112,7 +100,9 @@ metalsmith
|
|
|
112
100
|
|
|
113
101
|
### Standard Mode (default)
|
|
114
102
|
|
|
115
|
-
The plugin:
|
|
103
|
+
The plugin operates in two phases:
|
|
104
|
+
|
|
105
|
+
**Phase 1: HTML-Referenced Images**
|
|
116
106
|
|
|
117
107
|
1. Scans HTML files for image tags
|
|
118
108
|
2. Processes each image to create multiple sizes and formats
|
|
@@ -121,6 +111,13 @@ The plugin:
|
|
|
121
111
|
5. Adds width/height attributes to prevent layout shifts
|
|
122
112
|
6. Implements native lazy loading for better performance
|
|
123
113
|
|
|
114
|
+
**Phase 2: Background Images (when `processUnusedImages: true`)**
|
|
115
|
+
|
|
116
|
+
1. Finds images that weren't processed in Phase 1
|
|
117
|
+
2. Generates 1x/2x variants (half size and original size) for retina displays
|
|
118
|
+
3. Creates all configured formats (AVIF, WebP, original)
|
|
119
|
+
4. Suitable for use with CSS `image-set()` for background images
|
|
120
|
+
|
|
124
121
|
### Progressive Mode (experimental)
|
|
125
122
|
|
|
126
123
|
When `isProgressive: true` is enabled:
|
|
@@ -164,6 +161,9 @@ metalsmith.use(
|
|
|
164
161
|
// Custom output directory
|
|
165
162
|
outputDir: 'images/processed',
|
|
166
163
|
|
|
164
|
+
// Generate metadata manifest
|
|
165
|
+
generateMetadata: true, // Creates images/processed/responsive-images-manifest.json
|
|
166
|
+
|
|
167
167
|
// Don't add lazy loading
|
|
168
168
|
lazy: false
|
|
169
169
|
})
|
|
@@ -199,6 +199,79 @@ Add the `data-no-responsive` attribute to any image you don't want processed:
|
|
|
199
199
|
<img src="image.jpg" data-no-responsive alt="This image won't be processed" />
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
+
## Background Images
|
|
203
|
+
|
|
204
|
+
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`).
|
|
205
|
+
|
|
206
|
+
### How Background Processing Works
|
|
207
|
+
|
|
208
|
+
After processing HTML-referenced images, the plugin:
|
|
209
|
+
|
|
210
|
+
1. **Scans the Metalsmith files object** for all images
|
|
211
|
+
2. **Excludes already-processed images** (those found during HTML scanning)
|
|
212
|
+
3. **Excludes responsive variants** (generated images in the outputDir)
|
|
213
|
+
4. **Generates 1x/2x variants** using actual image dimensions:
|
|
214
|
+
- **1x variant**: Half the original size for regular displays
|
|
215
|
+
- **2x variant**: Original image size for retina displays (sharper on high-DPI screens)
|
|
216
|
+
5. **Creates all formats** (AVIF, WebP, original) for optimal browser support
|
|
217
|
+
|
|
218
|
+
### Using Background Images with CSS
|
|
219
|
+
|
|
220
|
+
For an image like `images/hero.jpg` (1920x1080 pixels), the plugin generates variants like:
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
assets/images/responsive/hero-960w.avif (1x - half 960px width for regular displays)
|
|
224
|
+
assets/images/responsive/hero-1920w.avif (2x - original 1920px width, sharper on retina)
|
|
225
|
+
assets/images/responsive/hero-960w.webp (1x - half 960px width for regular displays)
|
|
226
|
+
assets/images/responsive/hero-1920w.webp (2x - original 1920px width, sharper on retina)
|
|
227
|
+
assets/images/responsive/hero-960w.jpg (1x - half 960px width for regular displays)
|
|
228
|
+
assets/images/responsive/hero-1920w.jpg (2x - original 1920px width, sharper on retina)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Note**: Background images are generated **without hashes** for easier CSS authoring. HTML images still include hashes for cache-busting.
|
|
232
|
+
|
|
233
|
+
Use them in CSS with `image-set()`:
|
|
234
|
+
|
|
235
|
+
```css
|
|
236
|
+
.hero {
|
|
237
|
+
background-image: image-set(
|
|
238
|
+
url('/assets/images/responsive/hero-960w.avif') 1x,
|
|
239
|
+
url('/assets/images/responsive/hero-1920w.avif') 2x,
|
|
240
|
+
url('/assets/images/responsive/hero-960w.webp') 1x,
|
|
241
|
+
url('/assets/images/responsive/hero-1920w.webp') 2x,
|
|
242
|
+
url('/assets/images/responsive/hero-960w.jpg') 1x,
|
|
243
|
+
url('/assets/images/responsive/hero-1920w.jpg') 2x
|
|
244
|
+
);
|
|
245
|
+
background-size: cover;
|
|
246
|
+
background-position: center;
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Background Image Configuration
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
metalsmith.use(
|
|
254
|
+
optimizeImages({
|
|
255
|
+
// Standard HTML image processing
|
|
256
|
+
widths: [320, 640, 960, 1280, 1920],
|
|
257
|
+
formats: ['avif', 'webp', 'original'],
|
|
258
|
+
|
|
259
|
+
// Background image processing
|
|
260
|
+
processUnusedImages: true, // Enable background processing
|
|
261
|
+
|
|
262
|
+
// Generate metadata to see all variants
|
|
263
|
+
generateMetadata: true
|
|
264
|
+
})
|
|
265
|
+
);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Benefits of Background Image Processing
|
|
269
|
+
|
|
270
|
+
- **Automatic format optimization** - Browser selects best supported format
|
|
271
|
+
- **Retina display support** - 2x variants provide crisp images on high-DPI screens
|
|
272
|
+
- **No manual work** - Plugin automatically finds and processes unused images in Metalsmith files object
|
|
273
|
+
- **Consistent workflow** - Same formats and quality settings as HTML images
|
|
274
|
+
|
|
202
275
|
## Progressive Loading
|
|
203
276
|
|
|
204
277
|
### Overview
|
|
@@ -295,6 +368,37 @@ The plugin provides CSS for progressive loading, but you can customize it:
|
|
|
295
368
|
}
|
|
296
369
|
```
|
|
297
370
|
|
|
371
|
+
## Metadata Manifest
|
|
372
|
+
|
|
373
|
+
When `generateMetadata: true` is enabled, the plugin creates a JSON file at `{outputDir}/responsive-images-manifest.json` containing detailed information about all processed images:
|
|
374
|
+
|
|
375
|
+
```json
|
|
376
|
+
{
|
|
377
|
+
"images/hero.jpg": [
|
|
378
|
+
{
|
|
379
|
+
"path": "assets/images/responsive/hero-320w-a1b2c3d4.avif",
|
|
380
|
+
"width": 320,
|
|
381
|
+
"height": 180,
|
|
382
|
+
"format": "avif",
|
|
383
|
+
"size": 8432
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"path": "assets/images/responsive/hero-320w-a1b2c3d4.webp",
|
|
387
|
+
"width": 320,
|
|
388
|
+
"height": 180,
|
|
389
|
+
"format": "webp",
|
|
390
|
+
"size": 12658
|
|
391
|
+
}
|
|
392
|
+
]
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
This manifest is useful for:
|
|
397
|
+
|
|
398
|
+
- **Debugging**: Verify which variants were generated
|
|
399
|
+
- **Integration**: Use variant information in other tools
|
|
400
|
+
- **Performance analysis**: Compare file sizes across formats
|
|
401
|
+
|
|
298
402
|
## Debug
|
|
299
403
|
|
|
300
404
|
To enable debug logs, set the DEBUG environment variable to metalsmith-optimize-images\*:
|
|
@@ -318,30 +422,19 @@ metalsmith.env('DEBUG', 'metalsmith-optimize-images*');
|
|
|
318
422
|
}
|
|
319
423
|
```
|
|
320
424
|
|
|
321
|
-
##
|
|
322
|
-
|
|
323
|
-
This plugin is approaching 1.0.0 and we'd love your feedback! Please test and report:
|
|
324
|
-
|
|
325
|
-
### Especially Needed
|
|
326
|
-
|
|
327
|
-
- **Windows compatibility**: Sharp.js native compilation and image processing
|
|
328
|
-
- **Large image batches**: Performance with 50+ images
|
|
329
|
-
- **Memory usage**: Resource consumption in your environment
|
|
330
|
-
- **Cross-platform consistency**: Image quality and file sizes across platforms
|
|
331
|
-
- **Progressive loading**: Behavior across different browsers
|
|
425
|
+
## License
|
|
332
426
|
|
|
333
|
-
|
|
427
|
+
MIT
|
|
334
428
|
|
|
335
|
-
|
|
336
|
-
- ✅ Real Metalsmith integration tests (no mocks)
|
|
337
|
-
- ✅ Tested on macOS with Node.js 18+
|
|
338
|
-
- 🔄 Seeking broader platform validation
|
|
429
|
+
## Development transparency
|
|
339
430
|
|
|
340
|
-
|
|
431
|
+
Portions of this project were developed with the assistance of AI tools including Claude and Claude Code. These tools were used to:
|
|
341
432
|
|
|
342
|
-
|
|
433
|
+
- Generate or refactor code
|
|
434
|
+
- Assist with documentation
|
|
435
|
+
- Troubleshoot bugs and explore alternative approaches
|
|
343
436
|
|
|
344
|
-
|
|
437
|
+
All AI-assisted code has been reviewed and tested to ensure it meets project standards. See the included [CLAUDE.md](CLAUDE.md) file for more details.
|
|
345
438
|
|
|
346
439
|
[npm-badge]: https://img.shields.io/npm/v/metalsmith-optimize-images.svg
|
|
347
440
|
[npm-url]: https://www.npmjs.com/package/metalsmith-optimize-images
|
|
@@ -349,6 +442,6 @@ MIT
|
|
|
349
442
|
[metalsmith-url]: https://metalsmith.io
|
|
350
443
|
[license-badge]: https://img.shields.io/github/license/wernerglinka/metalsmith-optimize-images
|
|
351
444
|
[license-url]: LICENSE
|
|
352
|
-
[coverage-badge]: https://img.shields.io/badge/test%20coverage-
|
|
445
|
+
[coverage-badge]: https://img.shields.io/badge/test%20coverage-95%25-brightgreen
|
|
353
446
|
[coverage-url]: https://github.com/wernerglinka/metalsmith-optimize-images/actions/workflows/test.yml
|
|
354
447
|
[modules-badge]: https://img.shields.io/badge/modules-ESM%2FCJS-blue
|