Last active
March 31, 2022 06:30
-
-
Save stephenjbell/54b5876e24a9d7861c69873c6c9a0f30 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file goes in /src/transforms/ | |
// Add this line to .eleventy.js: | |
// const eleventyImgTransform = require("./src/transforms/eleventy-img-transform.js"); | |
// And add this one to module.exports in .eleventy.js: | |
// eleventyConfig.addTransform("eleventyImgTransform", eleventyImgTransform); | |
const Image = require("@11ty/eleventy-img"); | |
const cheerio = require("cheerio"); | |
const { resolve } = require("path"); | |
module.exports = (value, outputPath) => { | |
// Search for <img> on all pages matching this regex | |
// Only run on pages in the /dist/blog folder | |
if (outputPath.match(/^dist\/blog.*\.html$/)) { | |
let $ = cheerio.load(value); | |
// Find all the <img> within specified element, that don't have an HTML class | |
$(".article-text img:not([class])") | |
.not("picture > img") // Skip any <img> that's already wrapped in <picture> | |
.each(function (i, elem) { | |
let imgAlt = $(this).attr("alt") || ""; | |
let imgTitle = $(this).attr("title") || ""; | |
let imgSrc = $(this).attr("src"); | |
let imgLocation = "src" + imgSrc; | |
let fullImgLocation = resolve(imgLocation); | |
// TODO: Make this transform work when loading remote images | |
// Only process image if it's local | |
if (imgSrc.indexOf("http") == 0) { | |
return; | |
} | |
let options = { | |
// Each image size roughly 1.5X larger than last | |
widths: [250, 400, 600, 900, 1300], | |
formats: ["avif", "webp", "jpeg"], // In order of preference | |
outputDir: "dist/11ty-img/", | |
urlPath: "/11ty-img/", | |
}; | |
Image(fullImgLocation, options); // Start the images processing | |
let stats = Image.statsSync(fullImgLocation, options); // Get the locations where the processed images will appear | |
let lowestSrc = stats["jpeg"][0]; | |
let highestSrc = stats["jpeg"][stats["jpeg"].length - 1]; // The last JPG is the largest | |
let aspectRatio = highestSrc.width / highestSrc.height; | |
// Set the image width attribute to 800px, unless that's too large | |
let imageWidth = highestSrc.width; | |
if (highestSrc.width >= 800) { | |
imageWidth = 800; | |
} | |
// Set height to make the image the correct aspect ratio | |
let imageHeight = Math.ceil(imageWidth * aspectRatio); | |
// Iterate over formats and widths | |
let newElement = `<picture> | |
${Object.values(stats) | |
.map((imageFormat) => { | |
return ` <source type="image/${ | |
imageFormat[0].format | |
}" data-srcset="${imageFormat | |
.map((entry) => entry.srcset) | |
.join(", ")}">`; | |
}) | |
.join("\n")} | |
<img | |
data-src="${lowestSrc.url}" | |
data-sizes="auto" | |
width="${imageWidth}" | |
height="${imageHeight}" | |
class="lazyload" | |
title="${imgTitle}" | |
alt="${imgAlt}"> | |
</picture>`; | |
$(this).replaceWith(newElement); | |
}); | |
value = $.html(); | |
} | |
return value; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment