11ty / eleventy-img

Utility to perform build-time image transformations.
https://www.11ty.dev/docs/plugins/image/
436 stars 54 forks source link

Nunjucks shortcodes can't take variables as arguments when sourcing remote images #79

Closed Rocketpilot closed 2 years ago

Rocketpilot commented 3 years ago

Using a WordPress site as a data source. WordPress posts have featured images set.

Steps to reproduce:

  1. configure external datasource
  2. per documentation, configure addNunjucksAsyncShortcode that takes src, alt, sizes as parameters
  3. in the post template, grab featured image like so: {% set featuredImage = post._embedded['wp:featuredmedia']['0'].source_url | dump %}
  4. call this in the template {% image featuredImage, "external photo", "100" %}
  5. result:

Template render error was thrown

src is a required argument to the eleventy-img utility (can be a string file path, string URL, or buffer).

This would definitely work if I were using Twig. Throwing my hands up in the air. Tbh the Eleventy Img docs are a bit sparse when discussing templated usage of the tool.

Rocketpilot commented 3 years ago

Taking one of the image URLs as an example and adding that as a string for the src argument works as expected, generates locally cached image etc. I'm familiar with the Jinja syntax, at least in the Twig form, so I'd rather not try a different language. Does Liquid support variables as arguments?

ronykris commented 3 years ago

They look the same. I think there was a trick that worked. Eg: I had the following in frontmatter of the posts

`

imagePath: ./static/img/posts/pic.jpg alt: pic

`

Below is what I did in the njk.

{%set imgP = imagePath %} {% set imgAlt = alt %} {% Image ""+imgP, ""+imgAlt %}

Note the close and open double quotes in the example above.

It surprisingly worked :)

But this is a bug in my opinion.

Rocketpilot commented 3 years ago

That gives me a lot to go on, thank you. I’ve been stymied because I couldn’t find any trace of how to do concatenation in the official Nunjucks docs and the developers are actively hostile to variable interpolation. I’ll try this out and report back. And I agree it’s a bug.

Rocketpilot commented 3 years ago

Hmm it's not working for me...

I've set my example up as follows:

{% set featuredImage = post._embedded['wp:featuredmedia']['0'].source_url %}
{% set altText = "this is exhausting" %}
{% set imageSize = "100" %}

{% image ""+featuredImage, ""+altText, ""+imageSize %}

The resulting error message is:

`Template render error` was thrown:
    Error: ENOENT: no such file or directory, stat 'undefined'

Frustrating!

ronykris commented 3 years ago

Strange and sad. By the way, does it work without the first line?

Rocketpilot commented 3 years ago

You mean {% set featuredImage = post._embedded['wp:featuredmedia']['0'].source_url %}?

No, I tried using the original variable directly too, but interestingly the error was as follows:

parseSignature: expected comma after expression
Rocketpilot commented 3 years ago

Okay, yes it's still definitely a bug but the workaround a mate of mine pointed out is to wrap the image function call in an if statement:

{% if post._embedded['wp:featuredmedia']['0'].source_url|length %}
etc etc etc
{% endif %}

My next task is to figure out how to pull inline images from remote content post bodies into Image. Haha haha ahaha oh god.

zachleat commented 2 years ago

This is an automated message to let you know that a helpful response was posted to your issue and for the health of the repository issue tracker the issue will be closed. This is to help alleviate issues hanging open waiting for a response from the original poster.

If the response works to solve your problem—great! But if you’re still having problems, do not let the issue’s closing deter you if you have additional questions! Post another comment and we will reopen the issue. Thanks!

zachleat commented 2 years ago

After a full read here it seems like post._embedded['wp:featuredmedia']['0'].source_url didn’t have a value. The other thing you can do is change your image shortcode to check for a src and short circuit if it’s missing.

Rocketpilot commented 2 years ago

Not quite - it did have a value but it only rendered that value inside a conditional statement.

shirooo39 commented 2 years ago

so mine does work and corresponds to my frontmatter, but it only work if the image is from a url. once I feed it with local path, I'm getting the same template render error and also

ENOENT: no such file or directory, stat 'assets/images/covers/samantha-hendrata-wffp0K8sr7s-unsplash.jpg' (via Template render error)

assets/images/covers/samantha-hendrata-wffp0K8sr7s-unsplash.jpg doesn't work https://s4.anilist.co/file/anilistcdn/media/anime/banner/122808-1y799jBMv1VH.jpg this works

structure:

index.html

{% for post in collections.sortedPost %}
    <!-- other elements -->

    {% image post.data.cover, "Article Cover" %}

    <!-- other elements -->
{% endfor %}

posts.html (layouts)

<!-- other elements -->

{% image cover, "Article Cover" %}

<!-- other elements -->

article-01.md

---
layout: posts
title: Test Article 1
date: 2022-01-03
category: Test
cover: assets/images/covers/samantha-hendrata-wffp0K8sr7s-unsplash.jpg
---

.eleventy.js

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: [812],
        formats: ["webp"],
        outputDir: "site/assets/images",
        urlPath: '/assets/images',
    });

    let data = metadata.webp[metadata.webp.length - 1];

    return `<img class="md-card-media-cover" src="${data.url}" width="${data.width}" height="${data.height}" alt="${alt}" loading="lazy" decoding="async">`;
}

error:

[11ty] Problem writing Eleventy templates: (more in DEBUG output)
[11ty] 1. Having trouble rendering njk template ./source/index.html (via TemplateContentRenderError)
[11ty] 2. (./source/index.html)
[11ty]   EleventyShortcodeError: Error with Nunjucks shortcode `image` (via Template render error)
[11ty] 3. ENOENT: no such file or directory, stat 'assets/images/covers/samantha-hendrata-wffp0K8sr7s-unsplash.jpg' (via Template render error)
[11ty]
[11ty] Original error stack trace: Error: ENOENT: no such file or directory, stat 'assets/images/covers/samantha-hendrata-wffp0K8sr7s-unsplash.jpg'
[11ty]     at Object.statSync (node:fs:1588:3)
[11ty]     at Image.getInMemoryCacheKey (D:\Projects\GitHub\Shiro39\11ty-material\node_modules\@11ty\eleventy-img\img.js:156:32) 
[11ty]     at queueImage (D:\Projects\GitHub\Shiro39\11ty-material\node_modules\@11ty\eleventy-img\img.js:614:15)
[11ty]     at Object.imageShortcode (D:\Projects\GitHub\Shiro39\11ty-material\.eleventy.js:76:26)
[11ty]     at Object.<anonymous> (D:\Projects\GitHub\Shiro39\11ty-material\node_modules\@11ty\eleventy\src\BenchmarkGroup.js:32:26)
[11ty]     at ShortcodeFunction.run (D:\Projects\GitHub\Shiro39\11ty-material\node_modules\@11ty\eleventy\src\Engines\Nunjucks.js:266:14)
[11ty]     at eval (eval at _compile (D:\Projects\GitHub\Shiro39\11ty-material\node_modules\nunjucks\src\environment.js:633:18), 
<anonymous>:33:33)
[11ty]     at iterCallback (D:\Projects\GitHub\Shiro39\11ty-material\node_modules\nunjucks\src\runtime.js:293:11)
[11ty]     at next (D:\Projects\GitHub\Shiro39\11ty-material\node_modules\nunjucks\src\lib.js:328:7)
[11ty]     at Object.asyncIter (D:\Projects\GitHub\Shiro39\11ty-material\node_modules\nunjucks\src\lib.js:334:3)
[11ty] Wrote 0 files in 0.76 seconds (v1.0.2)
Rocketpilot commented 2 years ago

@shirooo39 my working theory is conditional statements are interpreted at the end of a page build so the image variable -- in certain situations -- is available by that point, which is why for me wrapping an image shortcode inside an if test works, but printing it directly does not work. I guess it's to do with when async items are processed in the rendering pipeline?

eystein commented 8 months ago

They look the same. I think there was a trick that worked. Eg: I had the following in frontmatter of the posts

imagePath: ./static/img/posts/pic.jpg
alt: pic

Below is what I did in the njk.

{%set imgP = imagePath %} {% set imgAlt = alt %} {% Image ""+imgP, ""+imgAlt %}

Note the close and open double quotes in the example above.

It surprisingly worked :)

But this is a bug in my opinion.

I don't understand why, but this works!