kit
kit copied to clipboard
Cannot pass "src" as prop while using @sveltejs/enhanced-img
Describe the bug
I wanted to created a simple hero component where I would pass the hero image dynamically, but I got error if enhanced:img used instead of img:
TypeError: Cannot read properties of undefined (reading 'src')
Code provided at "Reproduction" working correctly if I use simple img tag.
Reproduction
You need a JPG image named innerhero.jpg at /src/img/ folder
+page.svelte
<script>
import Hero from '$lib/template/Hero.svelte';
</script>
<Hero backgroundImage="$lib/img/innerhero.jpg" />
Hero.svelte
<script>
export let backgroundImage;
</script>
<enhanced:img src="{backgroundImage}" class="absolute inset-0 object-cover w-full h-full" alt="An alt text" />
I have also tried:
+page.svelte:
<script>
import Hero from '$lib/template/Hero.svelte';
import HeroImg from '$lib/img/innerhero.jpg';
</script>
<Hero backgroundImage="{HeroImg}" />
Logs
No response
System Info
System:
OS: Linux 5.15 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
CPU: (8) x64 Intel(R) Core(TM) i5-8350U CPU @ 1.70GHz
Memory: 4.02 GB / 7.69 GB
Container: Yes
Shell: 5.1.16 - /bin/bash
Binaries:
Node: 21.1.0 - ~/.nvm/versions/node/v21.1.0/bin/node
Yarn: 1.22.19 - /usr/bin/yarn
npm: 10.2.5 - ~/.nvm/versions/node/v21.1.0/bin/npm
pnpm: 8.12.1 - ~/.nvm/versions/node/v21.1.0/bin/pnpm
bun: 1.0.15 - ~/.bun/bin/bun
npmPackages:
@sveltejs/adapter-auto: ^3.1.0 => 3.1.0
@sveltejs/enhanced-img: ^0.1.7 => 0.1.7
@sveltejs/kit: ^2.0.6 => 2.0.6
@sveltejs/vite-plugin-svelte: ^3.0.1 => 3.0.1
svelte: ^4.2.8 => 4.2.8
vite: ^5.0.11 => 5.0.11
Severity
annoyance
Additional Information
No response
<script>
import Hero from '$lib/template/Hero.svelte';
</script>
<Hero backgroundImage="$lib/img/innerhero.jpg" />
This won't work because only enchanced:img
is preprocessed to convert the src
into an import.
<script>
import Hero from '$lib/template/Hero.svelte';
import HeroImg from '$lib/img/innerhero.jpg';
</script>
<Hero backgroundImage="{HeroImg}" />
Getting closer! You forgot the ?enhanced
query parameter though: https://kit.svelte.dev/docs/images#sveltejs-enhanced-img-dynamically-choosing-an-image
Is there a minimum working example somewhere we can play with / build from? (I have a blog where posts contain many images and I want image clicks to load a light table/gallery of all images on the page.)
I'm running into a similar issue, I can't get <enhanced:img>
to work as a re-usable component.
Here's what my code looks like:
// +page.svelte
<script lang="ts">
import Logo from '$lib/Logo.svelte';
import companyLogo from '$lib/images/logo.png?enhanced';
</script>
<Logo name="Some Company" src={companyLogo} />
// Logo.svelte
<script lang="ts">
export let name: string;
export let src: any;
</script>
<enhanced:img class="logo" alt={`${name} logo`} {src} />
<style lang="scss">
.logo {
// https://kit.svelte.dev/docs/images#sveltejs-enhanced-img-intrinsic-dimensions
width: var(--size);
height: auto;
}
</style>
The error this yields is:
2:37:50 PM [vite] Pre-transform error: Error while preprocessing /<path>/src/lib/Logo.svelte - Cannot read properties of undefined (reading 'trim')
If I use <enhanced:img>
directly in the +page.svelte
template everything works as expected.
For reference, I'm on "@sveltejs/enhanced-img": "^0.1.8"
@fmaclen could you provide a repository that reproduces this error? It's quite time consuming for us to copy code samples into projects for debugging given the number of open issues we have and so we tend to skip issues without repositories out of necessity
@benmccann here you go: https://github.com/fmaclen/enhancement-img-bug/
This is a npm create svelte@latest
generated skeleton repo with TypeScript and nothing else.
Only added dependency is @sveltejs/enhanced-img
.
EDIT: just added a commented implementation in +page.svelte
as the control group.
I'm travelling army the moment and don't have ready access to my computer but, looking at Fernando's repo, mine is functionally identical. My use case uses mdsvex, with the same issue, but is present in svelte also.
Thanks for looking into this. This is very useful functionality.
Dave.
Sent from Proton Mail mobile
-------- Original Message -------- On Jan. 17, 2024, 23:17, Ben McCann wrote:
@.***(https://github.com/fmaclen) could you provide a repository that reproduces this error? It's quite time consuming for us to copy code samples into projects for debugging given the number of open issues we have and so we tend to skip issues without repositories out of necessity
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>
I'm also running into this issue in combination with Markdoc preprocessing. I use <enhanced:img>
within a wrapper Svelte component. src
is provided by the wrapper component.
This is the error I got:
[plugin:vite-plugin-svelte] Error while preprocessing /path/to/src/lib/nodes/image.svelte - Cannot read properties of undefined (reading 'trim')
I guess the pre-processing step @benmccann mentioned further up is causing this.
I think @fmaclen's repro will also cover this case.
I also have a similar issue when trying to use <enhanced:img>
tag in sveltekit.
I have the latest versions:
-
"@sveltejs/enhanced-img": "^0.1.8"
-
"svelte": "^4.2.8",
What I'd like to do, is I'd like to pass strings from my backend, to the frontend, and simply render out a list of images using those strings.
Those string paths are references to images in my $libs/assets/
directory, see below:
<enhanced:img src={sheet.imagePath} alt={sheet.name} />
Where sheet.imagePath
would populate as ''/src/lib/assets/placeholder.jpg"
When I simply hardcode this entire string, I have no issue, but then again, that defats the purpose of what I'm trying to do. Any help?
Thanks!
I ran into the same issues with the enhanced:img
component. I created a repository to collect the error cases I was able to identify:
<script lang="ts">
import svelteLogo from '../images/svelte-logo-square.png?enhanced';
const fileName = "svelte-logo-square";
const fileExtension = "png";
const pathToFileTemplate = `../images/${fileName}.${fileExtension}`;
const pathToFile = '../images/svelte-logo-square.png';
</script>
<div>
<!-- these work fine -->
<enhanced:img src={svelteLogo} alt="" />
<enhanced:img src='../images/svelte-logo-square.png' alt="" />
<!-- these don't work -->
<enhanced:img src={'../images/svelte-logo-square.png'} alt="" />
<enhanced:img src={`../images/${fileName}.${fileExtension}`} alt="" />
<enhanced:img src={pathToFileTemplate} alt="" />
<enhanced:img src={pathToFile} alt="" />
</div>
@benmccann It seems like enhance-img
should be marked as a compiler plugin
in the docs, since it is not able to (at least currently) resolve any dynamically added vars during runtime (which has a big use-case).
EDIT: consider using the excellent svelte-img instead!
@fmaclen the example in your repository will work if you upgrade to 0.1.9. The issue was that we previously did not support the {src}
shorthand, but that's been implemented now
What I'd like to do, is I'd like to pass strings from my backend, to the frontend, and simply render out a list of images using those strings.
@DOZBORNE that is not supported. @sveltejs/enhanced-img
is a build plugin and the file must be located on the filesystem during build. If you get the path from a backend, CMS, database, etc. that's a different usecase that will not be addressed by @sveltejs/enhanced-img
. Please see https://kit.svelte.dev/docs/images#loading-images-dynamically-from-a-cdn for that usecase
@maiertech I'd like to support markdown, but I imagine you probably need some plugin for each markdown system. There's some discussion of that in https://github.com/sveltejs/kit/issues/11132. You could see if the discussion there is helpful to you or file a new issue with a repository that shows what you're trying to do. Let's handle that one outside of this issue as it's a different case than most of what's discussed here
@benmccann It seems like enhance-img should be marked as a compiler plugin in the docs, since it is not able to (at least currently) resolve any dynamically added vars during runtime (which has a big use-case).
I updated the docs in https://github.com/sveltejs/kit/pull/12058 to highlight this and you can now see them in https://kit.svelte.dev/docs/images
EDIT: consider using the excellent svelte-img instead!
The project is also a Vite plugin. It is built on top of vite-imagetools
, which I maintain, just like @sveltejs/enhanced-img
is. It is slightly different in that it uses an imported component rather than a preprocessor. That means that it only works with a syntax like import imageMeta from 'path/to/asset?as=run'
whereas this project supports both an import
syntax and referencing images in the src
attribute like <enhanced:img src="path/to/asset" />
I'm also hitting a similar issue: my goal is to automatically generate it for a list of images in the current folder in order to generate a static website. I tried to do:
import { error } from '@sveltejs/kit';
const imageModules = import.meta.glob("./img/*.jpg");
export const load = ({ params }) => {
let imgs = [];
for (const modulePath in imageModules) {
imageModules[modulePath]().then(({ default: imageUrl }) => {
imgs.push(modulePath);
});
}
return {imgs: imgs}
};
and then:
<script>
export let data;
</script>
<h1>Photos</h1>
<p>
Welcome
{#each data.imgs as img (img)}
{img}: <enhanced:img src={img} alt="foo" />
{/each}
</p>
but I also get an error… Is this supposed to be supported? (or can be made to be supported)
EDIT
Wait, just realized there is a section in the doc I'll try https://kit.svelte.dev/docs/images#sveltejs-enhanced-img-dynamically-choosing-an-image
EDIT2
I finally found the solution to create a mini-galery. It is just a bit technical cause import glob gives you a map file/promise, the promise import something, and then you still need to take the .default
. Demo: in the +page.js
:
import { error } from '@sveltejs/kit';
const imgsBlur = import.meta.glob(
'./img/*.{avif,gif,heif,jpeg,jpg,png,tiff,webp}',
{
query: {
enhanced: true,
blur: 3,
w: 100
}
}
);
const imgs = import.meta.glob(
'./img/*.{avif,gif,heif,jpeg,jpg,png,tiff,webp}',
{
query: {
enhanced: true,
}
}
);
export const load = async ({ params }) => {
const imgsBlurLoaded = await Promise.all(Object.entries(imgsBlur).map(async ([key, value]) => {
const img = await value();
return [key, img.default]
}));
const imgsLoaded = await Promise.all(Object.entries(imgs).map(async ([key, value]) => {
const img = await value();
return [key, img.default]
}));
return {imgsBlur: Object.fromEntries(imgsBlurLoaded),
imgsFull: Object.fromEntries(imgsLoaded)}
};
and in the page.svelte:
<script>
export let data;
let currentFullResImg;
</script>
<h1>Ma galerie</h1>
<p>
Bienvenue dans ma galerie
{#if currentFullResImg}
<enhanced:img src={data.imgsFull[currentFullResImg]} alt="Some alt text"/>
{/if}
{#each Object.entries(data.imgsBlur) as [path, img] (path)}
{path}: <enhanced:img src={img} alt="Some alt text" on:click={() => currentFullResImg = path} />
{/each}
</p>
Slightly cleaner version of @tobiasBora's fix that I used to make a custom component wrapper to enhance images in mdsvex (markdown importer).
Rolled the whole thing up into a single svelte component.
Posting here so if anyone else ends up at this issue trying to solve this problem for now, hopefully this helps.
<script context="module">
const images = import.meta.glob(['../images/**/*.{avif,gif,heif,jpeg,jpg,png,tiff,webp}'], {
eager: true,
query: { enhanced: true }
});
const get_full = (desired_image) => {
desired_image = '..' + desired_image;
return images[desired_image].default;
};
</script>
<script>
export let src;
export let alt = 'No alt available';
const image = get_full(src);
</script>
<figure class="image">
<enhanced:img src={image} {alt} />
</figure>
I'm sorry I am still really struggling with this one when attempting to pass enhanced images to a component. I can't seem to make it work with vite
or enhanced-img
The simple use case is,
+page.svelte
<script lang="ts">
import aqLogo from "$lib/assets/images/logo/aq.webp?enhanced";
import SimpleDark from "$lib/components/sections/logoclouds/SimpleDark.svelte";
</script>
<SimpleDark
heading = "Recognized by top industry leaders for excellence in medical education"
images = {[
{ src: {aqLogo}, alt: "AQ Solutions" }
....
]}
SimpleDark.svelte
<script lang="ts">
export let heading : string;
type ImageProps = {
src: any;
alt?: string;
};
export let images : ImageProps[];
</script>
...
<enhanced:img src={image.src} alt={image.alt} class="col-span-2 max-h-12 w-full object-contain lg:col-span-1" />
This just doesn't work with the following errors
TypeError: Cannot read properties of undefined (reading 'src')
Has anyone been able to make enhanced-img
work with Components
?
Looks like it's mad that you pass img
to the instantiation but declare the parameter as image
in Component
.
Also I'm not sure if enhanced img supports SVG as it's a vector format and not a typical bitmap image, you might run into that problem after fixing the naming issue.
Looks like it's mad that you pass
img
to the instantiation but declare the parameter asimage
inComponent
.Also I'm not sure if enhanced img supports SVG as it's a vector format and not a typical bitmap image, you might run into that problem after fixing the naming issue.
Sorry, that's what happens when you try and create a simple example...
Placed the real code in...
Do you have an extra set of curly braces around your images value (aqlogo) you're passing to the component?
I'd maybe try breakpointing or console.log-ing the value of images in your component and see what the value looks like.
I'm assuming there's an omitted "for image of images" in the component also?
Do you have an extra set of curly braces around your images value (aqlogo) you're passing to the component?
I'd maybe try breakpointing or console.log-ing the value of images in your component and see what the value looks like.
I'm assuming there's an omitted "for image of images" in the component also?
Sorry I wasted your time, you're correct, there were a slew of issues here in addition to the extra curly you mentioned
- Extra curly
- Can't use
svg
with@sveltejs/enhanced-img
- Can't mix and match (so even when I changed my
ImageProps.src : string | Picture
,<enhanced:img/>
hated it - Can't use
$lib
forsvg
images, had to move it understatic
with a different path
Regardless, my compliments to the package creators. Given the site I am working on will have north of a hundred images by the time I am finished, it's a life saver having this automated at build even with all its limitations.