metalsmith-adaptive-images
v1.1.0
Published
A plugin for Metalsmith to create adaptive images via srcset and styles properties
Downloads
6
Maintainers
Readme
metalsmith-adaptive-images
A plugin for Metalsmith to create adaptive images via
<img srcset="..." styles="..."/>
. It works well along with metalsmith-project-images.
Introduction
Providing images on websites nowadays can be tricky. You need to consider many different device sizes with good to to very bad connection speed.
So you will end up serving multiple versions of your images with different dimensions. Also you need to tell the browser which image to pick for a breakpoint. The article Don’t ruin your <img> - by Anthony Ng explains very well, what you need to keep in mind while serving images in today's web.
This plugin will create a map of images, containing metadata to properly output images with srcset and styles attributes.
It is up to you what to do with these informations. You can generate a gallery in your layout engine or use it your javascript to provide sharp images.
For simplicity, this module also provides a replace plugin, which replaces all matching images with their adaptive clones within html files.
Install
npm install --save metalsmith-adaptive-images
Preparation
First you need to load your images into metalsmith, you could use metalsmith-project-images for this.
To resize your images, you could use one of the following plugins for this:
- metalsmith-sharp - full sharp api integration
- metalsmith-image-resizer - simple sharp integration
- metalsmith-convert - old but good imagemagick
Also consider to compress your images. The metalsmith-imagemin plugin should be a good bet here. If you are looking for a very fast but effective JPEG compressor, I can really recommend to use mozjpeg.
Usage
If your environment does not support the import syntax, see further below.
The module consists of 2 metalsmith plugins and one method for rendering adaptive images. All of them can be used separately.
The processImages
plugin expects an array of images within the metadata of a file.
As soon as a matching metadata key is found, the plugin will create a new map of images with proper objects with the parsed and generated metadata.
It also provides the plugin replaceImages
to replace all images with their adaptive cousins in your html.
With renderImage
you will get a adaptive image based on the provided url and the given configuration.
import Metalsmith from 'metalsmith'
import images from 'metalsmith-project-images'
import AdaptiveImages from 'metalsmith-adaptive-images'
// Initialize your instance of the plugin.
// This allows you to use multiple configurations.
const adaptiveImages = AdaptiveImages({
... your configuration here ...
})
// Example #1: Enhance your image metadata
Metalsmith('/path/to/project')
// Use metalsmith-project-images to locate images and add to file metadata.
.use(images({}))
// Use the plugin to attach metadata.
// The default options match the ones of metalsmith-project-images.
.use(adaptiveImages.processImages)
.use(markdown()) // Generate html files out of your markdown
.use(layouts(...)) // Apply layouts to your files and add adaptive images manually.
.build()
// Example #2: Simply replace images
Metalsmith('/path/to/project')
.use(markdown()) // Generate html files out of your markdown
.use(adaptiveImages.replaceImages) // Replace images based on the given configuration above.
.build()
Every document with attached images like this:
files: {
'example.md': {
...,
images: [ 'images/example.jpg', ... ]
}
}
Will be transformed into this:
files: {
'example.md': {
...,
images: [ 'images/example.jpg', ... ]
imagesMap: {
'example.jpg': {
src: 'images/example-960.jpg',
srcset: 'images/example-1440.jpg 1440w, images/example-960.jpg 960w, images/example-480.jpg 480w',
sizes: '(min-width: 960px) 960px, 100vw',
name: 'example.jpg'
},
...
}
}
}
Node 6
const AdaptiveImages = require('metalsmith-adaptive-images')
Node 4
A version for the LTS version of node is also supplied. You can require it like this:
const AdaptiveImages = require('metalsmith-adaptive-images/dist/node4')
For further examples can be found in the test directory.
Options
If you got confused and need help to pick the correct options, this article about srcset and sizes may help you.
Default options:
{
imagesKey: 'images',
mapKey: 'imagesMap',
imageWidths: [1440, 960, 480],
imageSizes: ['(min-width: 960px) 960px', '100vw'],
defaultSize: 960,
namingPattern: '{dir}{name}-{size}{ext}', // foo/bar-200.jpg,...
srcsetPattern: '{url} {size}w' // foo/bar-200.jpg 200w,...
htmlFileGlob: '**/*.html',
htmlImageSelector: 'img'
}
imagesKey
The file metadata key where to look for images. metalsmith-project-images uses images
here, so does this plugin.
imagesMap
The file metadata key where to store the map of image objects.
imageWidths
Base value for the srcset attribute. This array represents the different image sizes, you want to provide. Together with the srcsetPattern
option the srcset attribute will be generated.
Make sure to define from biggest to lowest size to prevent issues with some browsers.
{
imageWidths: [2880, 1440, 960, 480, 320]
}
imageSizes
Values for the sizes attribute. This tells the browser, which size the image will have on the site. The values will be basically just combined to one string.
{
imageSizes: ['(min-width: 960px) 1440px', '100vw'],
}
defaultSize
Default size to select. The renderer will use this to set the src attribute and so should you. Older browsers will use this as fallback when they do not support the srcset attribute.
{
defaultSize: 960
}
namingPattern
Naming pattern for the actual image file names.
Supported placeholders:
{dir}
: Directory of file followed by slash{base}
: Full filename with extension{name}
: Filename without extension{ext}
: File extension with leading dot{size}
: The width of the current srcset breakpoint
{
namingPattern: '{dir}/{name}-{size}{ext}'
}
srcsetPattern
Pattern of the generated srcset syntax. The default should fit for most usecases.
Supported placeholders:
{url}
: The url of the image to serve for this breakpoint{size}
: The width of the current srcset breakpoint
{
srcsetPattern: '{url} {size}w'
}
htmlFileGlob
Glob to match html files whose images are going to be replaced by the replaceImages plugin. All minimatch features are supported.
{
htmlFileGlob: 'galleries/*.html'
}
htmlImageSelector
Selector to select images within the html files. Almost any jQuery selector pattern is support. See cheerio selectors documentation for more details.
{
htmlImageSelector: 'aside.gallery img'
}
Methods
processImages(files, metalsmith, done)
Metalsmith plugin to process the images found in the metadata of your files. Transforms an array of images to a proper map (object) with all information needed for adaptive display.
Thanks to this function, you can easily access your images within your page JS or in your templates to work with them.
replaceImages(files, metalsmith, done)
Metalsmith plugin to replace the images.
It will use cheerio to scan all html files for images and add the srcset and sizes attribute to them.
Change the htmlFileGlob
or
htmlImageSelector
option if you have special needs.
renderImage(src, attrs = {})
Renders a adaptive image with srcset and sizes attribute based on your configuration.
src
is the path to the image.attrs
is an object containing extra attributes for the image tag.
I found myself often using just this feature of the plugin, since the methods above are not needed in every case.
const adaptiveImages = AdaptiveImages()
adaptiveImages.renderImage('images/example.jpg', {
alt: 'alternative text',
title: 'title text'
})
Output since we did not pass any options:
<img
src="images/example-960.jpg"
srcset="images/example-1440.jpg 1440w, images/example-960.jpg 960w, images/example-480.jpg 480w"
sizes="(min-width: 960px) 960px, 100vw"
alt="alternative text" title="title text"/>
Development
This project follows the standard coding and the conventional changelog commit message style. Also it is configured to never decrease the code coverage of its tests.
Also make sure you check out all available npm scripts via npm run
.
Contributing
Pull requests and stars are always welcome. For bugs and feature requests, please create an issue. But before doing anything, please read the CONTRIBUTING.md guidelines.