Image
Low level utility to perform build-time image transformations for both vector and raster images. Output multiple sizes, save multiple formats, cache remote images locally. Uses the sharp image processor.
You maintain full control of your HTML—this plugin does not generate any markup. Use with <picture>
or <img>
or CSS background-image
, or others! Works great to add width
and height
to your images! Does not require or rely on file extensions (like .png
or .jpg
) in URLs or local files, which may be missing or inaccurate.
- Accepts:
jpeg
,png
,webp
,gif
,tiff
,avif
New in Image 0.6.0, andsvg
. - Output multiple sizes, keeps original aspect ratio. Never upscales raster images larger than original size (unless using SVG input).
- Output multiple formats, supports:
jpeg
,png
,webp
,avif
New in Image 0.6.0, andsvg
(requires SVG input) - Retrieve metadata about your new images (see sample return object).
- Use this to add
width
andheight
attributes on<img>
elements for proper aspect ratio mapping.
- Use this to add
- Save remote images locally using
eleventy-cache-assets
.- Use local images in your HTML to prevent broken image URLs.
- Manage the cache duration.
- De-duplicates and caches repeat calls using the same source image and the same output options. New in Image 0.7.0
- Manage plugin concurrency.
eleventy-img
on GitHub
- Installation
- Usage
- Output Widths
- Output Formats
- URL Path
- Output Directory
- Caching Remote Images Locally New in Image 0.3.0
- Skip raster formats for SVG New in Image 0.4.0
- Allow SVG to upscale New in Image 0.4.0
- Use this in your templates
- Synchronous Usage
- Advanced control of Sharp image processor
- Custom Filenames New in Image 0.4.0
- Caching
- Dry-Run New in Image 0.7.0
- Change Global Plugin Concurrency
Installation #
npm install --save-dev @11ty/eleventy-img
Usage #
This utility returns a Promise and works best in async
friendly functions, filters, shortcodes. It can also work in synchronous environments (Synchronous Usage).
const Image = require("@11ty/eleventy-img");
(async () => {
let url = "https://images.unsplash.com/photo-1608178398319-48f814d0750c";
let stats = await Image(url, {
widths: [300]
});
console.log( stats );
})();
Three things happen here:
- If the first argument is a full URL (not a local file path), we download the remote image and cache it locally using the Cache plugin. This cached original is then used for the cache duration to avoid a bunch of network requests.
- From that cached full-size original, images are created for each format and width, in this case:
./img/6dfd7ac6-300.webp
and./img/6dfd7ac6-300.jpeg
. - The metadata object is populated and returned, describing those new images:
{
webp: [
{
format: 'webp',
width: 300,
height: 300,
filename: '6dfd7ac6-300.webp',
outputPath: 'img/6dfd7ac6-300.webp',
url: '/img/6dfd7ac6-300.webp',
sourceType: 'image/webp',
srcset: '/img/6dfd7ac6-300.webp 300w',
size: 10184
}
],
jpeg: [
{
format: 'jpeg',
width: 300,
height: 300,
filename: '6dfd7ac6-300.jpeg',
outputPath: 'img/6dfd7ac6-300.jpeg',
url: '/img/6dfd7ac6-300.jpeg',
sourceType: 'image/jpeg',
srcset: '/img/6dfd7ac6-300.jpeg 300w',
size: 15616
}
]
}
Here’s the output images, one webp and one jpeg:
Output Widths #
Controls how many output images will be created for each image format. Aspect ratio is preserved.
widths: [null]
(default, keep original width)widths: [200]
(output one 200px width)widths: [200, null]
(output 200px and original width)
Output Formats #
Use almost any combination of these:
formats: ["webp", "jpeg"]
(default)formats: ["png"]
formats: [null]
(keep original format) New in Image 0.4.0formats: ["svg"]
(requires SVG input) New in Image 0.4.0formats: ["avif"]
New in Image 0.6.0
URL Path #
A path-prefix-esque directory for the <img src>
attribute. e.g. /img/
for <img src="/img/MY_IMAGE.jpeg">
:
urlPath: "/img/"
(default)
Output Directory #
Where to write the new images to disk. Project-relative path to the output image directory. Maybe you want to write these to your output directory directly (e.g. ./_site/img/
)?
outputDir: "./img/"
(default)
Caching Remote Images Locally New in Image 0.3.0 #
For any full URL first argument to this plugin, the full-size remote image will be downloaded and cached locally. See all relevant eleventy-cache-assets
options.
{
cacheOptions: {
// if a remote image URL, this is the amount of time before it fetches a fresh copy
duration: "1d",
// project-relative path to the cache directory
directory: ".cache",
removeUrlQueryParams: false,
},
}
Skip raster formats for SVG New in Image 0.4.0 #
If using SVG output (the input format is SVG and svg
is added to your formats
array), we will skip all of the raster formats even if they’re in formats
. This may be useful in a CMS-driven workflow when the input could be vector or raster.
svgShortCircuit: false
(default)svgShortCircuit: true
Allow SVG to upscale New in Image 0.4.0 #
While we do prevent raster images from upscaling (and filter upscaling widths
from the output), you can optionally enable SVG input to upscale to larger sizes when converting to raster format.
svgAllowUpscale: true
(default)svgAllowUpscale: false
Use this in your templates #
async
shortcode (different from the traditional shortcode configuration method). The JavaScript and Liquid template engines also work here and are asynchronous without additional changes. Note that Nunjucks macros cannot use asynchronous shortcodes. If you use macros, use Synchronous shortcodes described below.New in Image 0.7.2The generateHTML
function is available in Eleventy Image v0.7.2 or higher.
const Image = require("@11ty/eleventy-img");
async function imageShortcode(src, alt, sizes) {
let metadata = await Image(src, {
widths: [300, 600],
formats: ["avif", "jpeg"]
});
let imageAttributes = {
alt,
sizes,
loading: "lazy",
decoding: "async",
};
// You bet we throw an error on missing alt in `imageAttributes` (alt="" works okay)
return Image.generateHTML(metadata, imageAttributes);
}
module.exports = function(eleventyConfig) {
eleventyConfig.addNunjucksAsyncShortcode("image", imageShortcode);
eleventyConfig.addLiquidShortcode("image", imageShortcode);
eleventyConfig.addJavaScriptFunction("image", imageShortcode);
};
module.exports
in your configuration file! If one already exists, copy the content of the above into your existing module.exports
function.New in Image 0.7.3You can use the whitespaceMode
option to strip the whitespace from the output of the <picture>
element (a must-have for use in markdown files).
async function imageShortcode(src, alt, sizes) {
// […]
return Image.generateHTML(metadata, imageAttributes, {
whitespaceMode: "inline"
});
}
// Don’t copy and paste this code block!
// Some code from the above example was removed for brevity.
const Image = require("@11ty/eleventy-img");
async function imageShortcode(src, alt) {
if(alt === undefined) {
// You bet we throw an error on missing alt (alt="" works okay)
throw new Error(`Missing \`alt\` on myImage from: ${src}`);
}
let metadata = await Image(src, {
widths: [600],
formats: ["jpeg"]
});
let data = metadata.jpeg[metadata.jpeg.length - 1];
return `<img src="${data.url}" width="${data.width}" height="${data.height}" alt="${alt}" loading="lazy" decoding="async">`;
}
module.exports = function(eleventyConfig) {
eleventyConfig.addNunjucksAsyncShortcode("image", imageShortcode);
eleventyConfig.addLiquidShortcode("image", imageShortcode);
eleventyConfig.addJavaScriptFunction("image", imageShortcode);
};
module.exports
in your configuration file! If one already exists, copy the content of the above into your existing module.exports
function.const Image = require("@11ty/eleventy-img");
async function imageShortcode(src, alt, sizes = "100vw") {
if(alt === undefined) {
// You bet we throw an error on missing alt (alt="" works okay)
throw new Error(`Missing \`alt\` on responsiveimage from: ${src}`);
}
let metadata = await Image(src, {
widths: [300, 600],
formats: ['webp', 'jpeg']
});
let lowsrc = metadata.jpeg[0];
let highsrc = metadata.jpeg[metadata.jpeg.length - 1];
return `<picture>
${Object.values(metadata).map(imageFormat => {
return ` <source type="${imageFormat[0].sourceType}" srcset="${imageFormat.map(entry => entry.srcset).join(", ")}" sizes="${sizes}">`;
}).join("\n")}
<img
src="${lowsrc.url}"
width="${highsrc.width}"
height="${highsrc.height}"
alt="${alt}"
loading="lazy"
decoding="async">
</picture>`;
}
module.exports = function(eleventyConfig) {
eleventyConfig.addNunjucksAsyncShortcode("image", imageShortcode);
eleventyConfig.addLiquidShortcode("image", imageShortcode);
eleventyConfig.addJavaScriptFunction("image", imageShortcode);
};
module.exports
in your configuration file! If one already exists, copy the content of the above into your existing module.exports
function.Now you can use it in your templates:
{% image "./src/images/cat.jpg", "photo of my cat" %}
{% image "./src/images/cat.jpg", "photo of my cat", "(min-width: 30em) 50vw, 100vw" %}
The comma between arguments is required in Nunjucks templates.
{% image "./src/images/cat.jpg", "photo of my cat" %}
{% image "./src/images/cat.jpg", "photo of my cat", "(min-width: 30em) 50vw, 100vw" %}
The comma between arguments is optional in Liquid templates.
module.exports = function() {
return `<h1>${await this.image("./src/images/cat.jpg", "photo of my cat", "(min-width: 30em) 50vw, 100vw")}</h1>`;
};
And you’ll have the appropriate HTML generated for you (based on your specified Image options).
Synchronous Usage #
Use Image.statsSync
to get the metadata of a source even if the image
generation is not finished yet:
const Image = require("@11ty/eleventy-img");
function imageShortcode(src, cls, alt, sizes, widths) {
let options = {
widths: widths,
formats: ['jpeg'],
};
// generate images, while this is async we don’t wait
Image(src, options);
let imageAttributes = {
class: cls,
alt,
sizes,
loading: "lazy",
decoding: "async",
};
// get metadata even the images are not fully generated
let metadata = Image.statsSync(src, options);
return Image.generateHTML(metadata, imageAttributes);
}
module.exports = function(eleventyConfig) {
eleventyConfig.addNunjucksShortcode("myImage", imageShortcode);
}
Advanced control of Sharp image processor #
Extra options to pass to the Sharp constructor or the Sharp image format converter for webp, png, jpeg, or avif.
sharpOptions: {}
New in Image 0.4.0sharpWebpOptions: {}
New in Image 0.4.2sharpPngOptions: {}
New in Image 0.4.2sharpJpegOptions: {}
New in Image 0.4.2sharpAvifOptions: {}
New in Image 0.6.0
Custom Filenames New in Image 0.4.0 #
Don’t like those hash ids? Make your own!
{
// Define custom filenames for generated images
filenameFormat: function (id, src, width, format, options) {
// id: hash of the original image
// src: original image path
// width: current width in px
// format: current file format
// options: set of options passed to the Image call
return `${id}-${width}.${format}`;
}
}
Custom Filename Example: Use the original file slug
const path = require("path");
const Image = require("@11ty/eleventy-img");
await Image("./test/bio-2017.jpg", {
widths: [300],
formats: [null],
filenameFormat: function (id, src, width, format, options) {
const extension = path.extname(src);
const name = path.basename(src, extension);
return `${name}-${width}w.${format}`;
}
});
// Writes: "test/img/bio-2017-300w.jpeg"
Caching #
In-Memory Cache New in Image 0.7.0 #
To prevent duplicate work and improve build performance, repeated calls to the same source image (remote or local) with the same options will return a cached results object. If a request in-progress, the pending promise will be returned. This in-memory cache is maintained across builds in watch/serve mode.
Images will be regenerated (and the cache ignored) if:
- The source image file size changes (on local image files)
- The cache asset duration expires (for remote images).
You can disable this behavior by using the useCache
boolean option:
useCache: true
(default)useCache: false
to bypass the cache and generate a new image every time.
Examples
Example of in-memory cache reuse (returns the same promise)
const Image = require("@11ty/eleventy-img");
(async () => {
let stats1 = Image("./test/bio-2017.jpg");
let stats2 = Image("./test/bio-2017.jpg");
console.assert(stats1 === stats2, "The same promise");
})();
Example of in-memory cache (returns a new promise with different options)
const Image = require("@11ty/eleventy-img");
(async () => {
let stats1 = Image("./test/bio-2017.jpg");
let stats2 = Image("./test/bio-2017.jpg", { widths: [300] });
console.assert(stats1 !== stats2, "A different promise");
})();
Disk Cache New in Image 1.0.0 #
Starting in Eleventy Image 1.0 (when using the built-in hashing algorithm and not custom filenames), Eleventy will skip processing files that are unchanged and already exist in the output directory. While the previously available in-memory cache avoided processing across repeat builds during --watch
and --serve
, this will avoid processing unchanged files for all builds. Read more at Issue #51.
Dry-Run New in Image 0.7.0 #
If you want to try it out and not write any files (useful for testing), use the dryRun
option.
dryRun: false
(default)dryRun: true
Change Global Plugin Concurrency #
const Image = require("@11ty/eleventy-img");
Image.concurrency = 4; // default is 10