Created
May 8, 2020 12:40
-
-
Save polarbirke/d9a946ad7005a5a7e46f9e8502b1f875 to your computer and use it in GitHub Desktop.
11ty (eleventy) plugin to automagically inject image height and width attributes
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
| /** | |
| * eleventy-plugin-imgdimensions | |
| * | |
| * Totally stolen from https://github.com/liamfiddler/eleventy-plugin-lazyimages | |
| * but with a lot less features; this tiny version only injects width and height | |
| * attributes to img tags! | |
| * | |
| * - NO srcset support! | |
| * - NO lazyloading! | |
| * - NO placeholders! | |
| * | |
| * @type {module:fs} | |
| */ | |
| const fs = require('fs'); | |
| const url = require('url'); | |
| const path = require('path'); | |
| const { JSDOM } = require('jsdom'); | |
| const Jimp = require('jimp'); | |
| const supportedExtensions = [ | |
| 'jpg', | |
| 'jpeg', | |
| 'gif', | |
| 'png', | |
| 'bmp', | |
| 'tiff', | |
| 'webp', | |
| ]; | |
| const transformImgPath = (src) => { | |
| if (src.startsWith('/') && !src.startsWith('//')) { | |
| return `.${src}`; | |
| } | |
| return src; | |
| }; | |
| const defaultImgDimensionsConfig = { | |
| imgSelector: 'img', | |
| transformImgPath, | |
| cacheFile: '.imgdimensions.json', | |
| }; | |
| let imgDimensionsConfig = defaultImgDimensionsConfig; | |
| let imgDimensionsCache = {}; | |
| const logMessage = (message) => { | |
| console.log(`ImgDimensions - ${message}`); | |
| }; | |
| const loadCache = () => { | |
| const { cacheFile } = imgDimensionsConfig; | |
| if (!cacheFile) { | |
| return; | |
| } | |
| try { | |
| if (fs.existsSync(cacheFile)) { | |
| const cachedData = fs.readFileSync(cacheFile, 'utf8'); | |
| imgDimensionsCache = JSON.parse(cachedData); | |
| } | |
| } catch(e) { | |
| console.error('ImgDimensions: cacheFile', e); | |
| } | |
| }; | |
| const readCache = (imageSrc) => { | |
| if (imageSrc in imgDimensionsCache) { | |
| return imgDimensionsCache[imageSrc]; | |
| } | |
| return undefined; | |
| }; | |
| const updateCache = (imageSrc, imageData) => { | |
| const { cacheFile } = imgDimensionsConfig; | |
| imgDimensionsCache[imageSrc] = imageData; | |
| if (cacheFile) { | |
| const cacheData = JSON.stringify(imgDimensionsCache); | |
| fs.writeFile(cacheFile, cacheData, (err) => { | |
| if (err) { | |
| console.error('ImgDimensions: cacheFile', e); | |
| } | |
| }); | |
| } | |
| }; | |
| const getImageData = async imageSrc => { | |
| let imageData = readCache(imageSrc); | |
| if (imageData) { | |
| return imageData; | |
| } | |
| logMessage(`started processing ${imageSrc}`); | |
| const image = await Jimp.read(imageSrc); | |
| const width = image.bitmap.width; | |
| const height = image.bitmap.height; | |
| imageData = { | |
| width, | |
| height, | |
| }; | |
| logMessage(`finished processing ${imageSrc}`); | |
| updateCache(imageSrc, imageData); | |
| return imageData; | |
| }; | |
| const processImage = async imgElem => { | |
| const { transformImgPath, className } = imgDimensionsConfig; | |
| const imgPath = transformImgPath(imgElem.src); | |
| const fileExt = path.extname(url.parse(imgPath).pathname).substr(1); | |
| if (!supportedExtensions.includes(fileExt.toLowerCase())) { | |
| logMessage(`${fileExt} placeholder not supported: ${imgPath}`); | |
| return; | |
| } | |
| try { | |
| const image = await getImageData(imgPath); | |
| imgElem.setAttribute('width', image.width); | |
| imgElem.setAttribute('height', image.height); | |
| } catch (e) { | |
| console.error('ImgDimensions', imgPath, e); | |
| } | |
| }; | |
| const transformMarkup = async (rawContent, outputPath) => { | |
| const { imgSelector } = imgDimensionsConfig; | |
| let content = rawContent; | |
| if (outputPath && outputPath.endsWith('.html')) { | |
| const dom = new JSDOM(content); | |
| const images = [...dom.window.document.querySelectorAll(imgSelector)]; | |
| if (images.length > 0) { | |
| logMessage(`found ${images.length} images in ${outputPath}`); | |
| await Promise.all(images.map(processImage)); | |
| logMessage(`processed ${images.length} images in ${outputPath}`); | |
| content = dom.serialize(); | |
| } | |
| } | |
| return content; | |
| }; | |
| module.exports = { | |
| initArguments: {}, | |
| configFunction: (eleventyConfig, pluginOptions = {}) => { | |
| imgDimensionsConfig = Object.assign( | |
| {}, | |
| defaultImgDimensionsConfig, | |
| pluginOptions | |
| ); | |
| loadCache(); | |
| eleventyConfig.addTransform('imgdimensions', transformMarkup); | |
| }, | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment