xiphux / svimg

Svelte image component with image preprocessing and lazy loading
ISC License
245 stars 15 forks source link

'Input file is missing' when `src` is a variable #13

Open hmaesta opened 3 years ago

hmaesta commented 3 years ago
<script>
   import Image from 'svimg';
   const src = 'images/birds/orange-bird.jpg';
</script>

<Image {src} />

Like above example, when src is a variable the Input file is missing error is returned.

It also doesn't work when in a loop, like:

<script>
   import Image from 'svimg';
   const animals = [ 'dogs.jpg', 'cats.jpg', 'birds.jpg' ]
</script>

{#each animals as animal}
   <Image src={animal} />
{/each}

That makes impossible to load images from a JSON file, for instance, or using svimg in a repeatable component.


Broken code examples:

I couldn't get a running example online since build breaks with "Input file is missing".

xiphux commented 3 years ago

I can maybe add a note to the documentation but svimg only works with literal image paths and this might be impossible to do automatically. The svelte preprocessor can only preprocess the source code but cannot really execute the Svelte/javascript code, so it cannot actually interpret the end result of this javascript.

hmaesta commented 3 years ago

That makes sense... 😓

I went for some "benchmarking" and found that:

Here's a sandbox to show nuxt/image working with a loop.

xiphux commented 3 years ago

I would guess that Nuxt-image hooks into Nuxt's SSR process when the code is actually executed server side. The Svelte preprocessing hook is more for transformation of source code (eg Typescript to Javascript), not actual server side rendering. Since the SSR is being handled by SvelteKit, I would imagine it would require a SvelteKit-specific solution to hook into SSR (if SvelteKit even provides a way to do that - not sure).

In cases like this where I've needed to process images that don't live in the markup, I've thrown together plugins to make use of the svimg preprocessor in other places besides the standard Svelte preprocessing hook, and I added support for svimg to be used as an <s-image> custom element specifically for dynamic use cases like this.

For example, my personal site using svimg is written in Markdown for all of the content. So I put together:

These plugins really just call into a couple exported svimg functions to do all the image generation and get back the appropriate attributes for the component.

So off of the top of my head, if you have images in JSON files, you could potentially have a build plugin that reads your JSON files, runs them through svimg, and adds the generated attributes as additional JSON properties. Then, you could consume that JSON in your Svelte component and set all those attributes including the generated ones onto the component during render.

rchrdnsh commented 2 years ago

hmmmm…would you say that kit needs to do this then? Is this kind of thing only possible at the framework level? Been looking for something to solve this usecase, as it is most of my need in regards to images. Maybe…I dunno 70-90% of the time I am rendering images in {#each} blocks…

xiphux commented 2 years ago

Well, it'd have to be hooked into the rendering process in some way to know what the result of your dynamic expressions are. So I think it'd have to be svimg plugging into the sveltekit render process somewhere, but I haven't looked into it yet to know where that is specifically (ie what's best way to hook into the SSR process - I assume there's some way). I've generally tried to stay framework-agnostic, but if there's enough demand I could certainly look into it.

It's also worth thinking about alternative ways to do this. For example, even though your image elements may be rendered in a loop, don't your images live on disk somewhere? (The images aren't generated from nothing, are they?) Can you have a build plugin that uses node apis to get all image files in a directory and run them through to generate the files and component attributes (like the packages in my previous comment do). You could then store off those generated attributes somewhere that your Svelte code could import (like a JSON file or something), and then make use of them with svimg's Custom Element.

indaco commented 2 years ago

it's a shame!

I also tried to use the combo "mdsvex + rehype-svimg" for single page without success

rchrdnsh commented 2 years ago

what I'm doing now is this:

---
order: 2
status: marquee
category: words
title: Time
subtitle: Music starts here.
description: 
image: /words/time/time.jpg
alt: Flying at the speed of sound.
---

<script context="module">
  import Clock from '$lib/special/Clock.svelte';
  metadata.animated_image = Clock;

  metadata.srcset_portrait_jpg = TimePortraitJPG;
  metadata.srcset_landscape_jpg = TimeLandscapeJPG;
</script>

where I use vite-imagetools to manually make a srcset for the images in question in their markdown files...I don't have a workflow for looping through images in a svelte file yet, though...

but all of this is quite a manual pain and might not work at all if pulling form a cms or some other data source...

I had not thought about a build plugin, nor do I know really know what that is or how to make one...

If you have any resources or suggestions on that I would be glad to check it out :-)

Ideally I want kit or something else to process images automatically and only when new ones are added or changed on my local device which would then sync up with whatever host I'm using without making the host build the images

for example, I was trying to use AVIF images in this process but Netlify simply would not do it, as it was too costly and time consuming and memory consuming to do so...

indaco commented 2 years ago

In my case the frontmatter variable contains just the file name without the path to it

The path is built based on the sveltekit route the md file is belong to, so should not be hardcoded as frontmatter variable.

what I'm doing now is this:


---

order: 2

status: marquee

category: words

title: Time

subtitle: Music starts here.

description: 

image: /words/time/time.jpg

alt: Flying at the speed of sound.

---

<script context="module">

  import Clock from '$lib/special/Clock.svelte';

  metadata.animated_image = Clock;

  metadata.srcset_portrait_jpg = TimePortraitJPG;

  metadata.srcset_landscape_jpg = TimeLandscapeJPG;

</script>

where I use vite-imagetools to manually make a srcset for the images in question in their markdown files...I don't have a workflow for looping through images in a svelte file yet, though...

but all of this is quite a manual pain and might not work at all if pulling form a cms or some other data source...

I had not thought about a build plugin, nor do I know really know what that is or how to make one...

If you have any resources or suggestions on that I would be glad to check it out :-)

Ideally I want kit or something else to process images automatically and only when new ones are added or changed on my local device which would then sync up with whatever host I'm using without making the host build the images

for example, I was trying to use AVIF images in this process but Netlify simply would not do it, as it was too costly and time consuming and memory consuming to do so...

rchrdnsh commented 2 years ago

yeah, my content lives in it's own content folder, and is not co-located in the routes, but gets injected into templates later on...the image path is for the static folder anyway, so...

xiphux commented 2 years ago

There's a lot going on in this issue discussion...

If you're having issues with rehype-svimg, I would suggest putting issues on that repo instead. This issue was supposed to represent the more general limitation around dynamic expressions in the img src and not around directory layout or markdown files.

As of right now, I don't believe this component's preprocessor is compatible with vite-imagetools. By build plugin, I'm referring to a plugin for your app bundling pipeline, whether that's vite or rollup or something else. I had created rollup-plugin-markdown-svimg some time ago, before svelte adopted vite, with the idea being that rehype-svimg was used during markdown rendering to html to convert markdown image format (!(Image caption)[url/to/image.jpg]) to an svimg element, and during bundling the rollup plugin would handle generating the actual image files. Maybe that doesn't work or make sense for your scenario, but that's what I mean by handling it elsewhere in a build plugin.

svimg will only generate images that don't already exist. I'm not familiar with Netlify and its deployment process at all, but you could consider pregenerating the images and committing them to source control if you don't want them to be recreated.

I have a similar directory layout, where routes are in one directory, markdown content is in another, and images are in a static image third directory. My markdown files also similarly reference image filenames without a path, and I added the srcPrefix option to let the render process control where the image lives. So the route file reads the markdown from the relevant content directory, using the srcPrefix to point image urls to the static image directory.

I'm happy to help more with getting rehype-svimg working for markdown images if that's what you're looking for, but it'd be helpful if: