eleventy-img icon indicating copy to clipboard operation
eleventy-img copied to clipboard

Image: using statsByDimensionsSync produces invalid HTML

Open brettdewoody opened this issue 1 year ago • 1 comments

Operating system

macOS Catalina 10.15.7

Eleventy

2.0

Describe the bug

I'm trying to create a syncronous shortcode to generate a banner image. The image is a remote URL (from Sanity) so instead of statsSync it says to use statsByDimenionsSync. This results in invalid HTML when using the Image.generateHTML method:

<picture>
  <source type="image/webp" srcset="/img/FnYZGJrra8-[object Object].webp [object Object]w" sizes="(max-width: 0px) 100vw">
  <img alt="Surly Wednesday" loading="lazy" decoding="async" fetchpriority="high" class="w-full h-full object-cover" src="/img/FnYZGJrra8-[object Object].jpeg" width="[object Object]" height="NaN">
</picture>

The structure of the metadata widths is different than produced with statsSync.

Should we be able to use statsByDimensionsSync with Image?

Reproduction steps

  1. Add a shortcode file containing
const Image = require('@11ty/eleventy-img')

const bannerImageShortcode = (
  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}`)
  }
  const options = {
    widths: [700, 1200, 2000],
    formats: ['avif', 'jpeg'],
    outputDir: './_site/img/',
    urlPath: '/img/',
    cacheOptions: {
      duration: '1d',
    },
  }

  Image(src, options)
  let metadata

  try {
    const isURL = new URL(src)
    metadata = Image.statsByDimensionsSync(src, options)
  } catch (_) {
    metadata = Image.statsSync(src, options)
  } 

  const imageAttributes = {
    alt,
    sizes: '(max-width: 0px) 100vw',
    loading: 'lazy',
    decoding: 'async',
    fetchPriority: 'high',
    class: 'w-full h-full object-cover',
  }

  console.log(Object.values(metadata).map(formats => formats[0]))

  return Image.generateHTML(metadata, imageAttributes)
}

module.exports = bannerImageShortcode
  1. Add the shortcode to your Eleventy config
const bannerImageShortcode = require('./src/utils/shortcodes/shortcodeBannerImage')
module.exports = function (eleventyConfig) {
  ...
  eleventyConfig.addNunjucksShortcode('bannerImage', bannerImageShortcode)
}
  1. Use the shortcode in template
  {% bannerImage '[some remote image URL], 'Brands' %}
  1. See the invalid HTML output

Expected behavior

A valid picture element

Reproduction URL

No response

Screenshots

No response

brettdewoody avatar Mar 13 '23 10:03 brettdewoody

Sorry to ask a semi-unrelated question here but do you need to use the synchronous method here? The async method is recommended: https://www.11ty.dev/docs/plugins/image/#asynchronous-shortcode

zachleat avatar Mar 27 '23 21:03 zachleat