Skip to content

Instantly share code, notes, and snippets.

@tkroo
Last active March 27, 2023 23:56
Show Gist options
  • Save tkroo/02960e4212f62489f521f070e35e6c9b to your computer and use it in GitHub Desktop.
Save tkroo/02960e4212f62489f521f070e35e6c9b to your computer and use it in GitHub Desktop.
const fs = require("fs");
const path = require("path");
const sharp = require("sharp");
const formats = ['avif', 'webp','jpg'];
const formatsQuality = [40, 50, 50];
const myroot = process.env.ELEVENTY_ROOT;
// USE
// this:
// {%- imageOptimize item.img, item.title, "394, 564", "(max-width:600px) 100vw, 394px", true -%}
// will generate:
// <picture>
// <source type="image/avif" srcset="/images/work/wwf1-394w.avif 394w, /images/work/wwf1-564w.avif 564w" sizes="(max-width:600px) 100vw, 394px">
// <source type="image/webp" srcset="/images/work/wwf1-394w.webp 394w, /images/work/wwf1-564w.webp 564w" sizes="(max-width:600px) 100vw, 394px">
// <img class="img--full" alt="Winter Water Factory" loading="eager" decoding="async" srcset="/images/work/wwf1-394w.jpg 394w, /images/work/wwf1-564w.jpg 564w" src="/images/work/wwf1-394w.jpg" sizes="(max-width:600px) 100vw, 394px" width="564" height="564">
// </picture>
function processImage (fullInPath, outputFile, mywidth, f) {
const image = sharp(fullInPath)
.resize({
fit: sharp.fit.contain,
width: mywidth
})
.toFormat(formats[f], {quality: formatsQuality[f]})
.toFile(outputFile)
}
function createPictureElement(src, mywidths, sizes, alt, nolazy) {
const po = path.parse(src);
const srcsetsArr = [];
formats.forEach(format => {
srcsetsArr.push(mywidths.map(width => `${path.join(po.dir, po.name+"-"+width+"w."+format)} ${width}w`).join(', '));
})
const lastFormatSuffix = `w.${formats[formats.length-1]}`;
const minWidth = Math.min(...mywidths);
const maxWidth = Math.max(...mywidths);
let output = `<picture>`;
for (let i = 0; i < formats.length; i++) {
if(i < formats.length-1) {
output += `<source type="image/${formats[i]}" srcset="${srcsetsArr[i]}" sizes="${sizes}">`
} else {
let mysrc = `${src.replace(po.ext, "-" + minWidth + lastFormatSuffix)}`;
output += `<img class="img--full" alt="${alt}" loading="${nolazy ? 'eager' : 'lazy'}" decoding="async"
srcset="${srcsetsArr[i]}"
src="${mysrc}" width="${maxWidth}" height="${maxWidth}"
sizes="${sizes}"
>
</picture>`
}
}
return output;
}
module.exports = {
imageOptimize: function(src, alt, widths, sizes, nolazy) {
const mywidths = widths.split(',').map(s => parseInt(s));
const outputDir = path.join(myroot,'_site', path.parse(src).dir);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true })
}
for (let f=0; f < formats.length; f++) {
for (let i=0; i < mywidths.length; i++) {
const fullInPath = path.join(myroot,"src/_assets", src);
const outputFile = path.join(outputDir, path.parse(src).name+"-"+mywidths[i]+"w."+formats[f] );
fs.access(outputFile, error => {
if(error) {
console.log("Optimizing", src, "to", outputFile);
processImage(fullInPath, outputFile, mywidths[i], f)
} else {
// console.log('file already exists. nothing to be done.');
}
})
}
}
return createPictureElement(src, mywidths, sizes, alt, nolazy);
},
getYear: () => `${new Date().getFullYear()}`
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment