-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Image processing #241
Comments
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Maybe — need to take a look and see if there's anything missing from this: https://twitter.com/rchrdnsh/status/1336386125552779264 |
That description isn't very helpful, does the plugin transform the sourcecode as well as optimising the image? If it only does the image optimisation, it would be pretty limiting in terms of lazy-loading, generating srcsets, etc. Likewise some way to set the priority of the image (by adding preload tags to the head) would also be good. Image components aren't always the best solution but they offer a lot of flexibility depending on your needs. |
I think the most comprehensive implementations will need to be framework specific, although I haven't thought about it a great deal. |
With regards to this, I think a rollup/vite plugin for https://www.npmjs.com/package/sharp would likely be able to fulfil these requirements. |
Hi all, thank you for considering this feature... Just found this new (2 months old, it seems) plugin for Vite...starting to mess around with it with no success yet...seems potentially promising, however :-) |
I'm in a close contact with the author and he's rewriting the whole library into core library and different bundler adapters including vite. You can easily just do this to generate 6 different images together with their width and height info: import {width, height, src} from "./image.jpg?format=webp;jpg&width=480;1024;1920&metadata" |
Hey guys! I'm a little late to the party, but whatever 👋🏻
vite-imagetools (or the core library more specifically) is basically just a wrapper around sharp, that let's you "execute" sharps image function in the import statement. The basic idea though is to provide a "common api" that lets you specify how you want your image to be transformed and all the rest (wether the transformation is done by sharp or libvips directly, what buildtools you use, etc.) are completely irrelevant to the developer as all information is encoded in the url and not some config file. It's not super reliable in vite yet(because vite is sometimes a bit quirky with static assets) |
@JonasKruckenberg really appreciate your work on the vite-imagetools library. I was able to get vite-imagetools integrated with the current release of sveltekit and the node adapter!
Edit: With srcset:
|
Is it a better idea to put your images like this in the |
Definitely; I will likely end up moving them to src/static and updating svelte.config.cjs to reflect the updated location of the static assets. |
hmmmm... might it be worth considering adding some sort of official Svelte/Kit support for some sort of |
What more is SvelteKit supposed to do than is already possible per the comment above? |
well, i don't have to make a |
Example integration of vite-imagetools and sveltekit with $static alias for src/static below:
|
very nice :-) We should probably move this kind of stuff to discord, but thank you! |
There is so much boilerplate to write, even more if you need backward compatibility with WebP in a picture tag. But since svelte is a compiler, can't we just have an image transformation attribute right on the img tag that can create whatever we want - including lazy loading or fade-in transitions and more? |
Well I went down the rabbit hole of trying to use vite-imagetools with SvelteKit yesterday. I have a site using Netlify CMS with local JSON files and wanted to dynamically load and resize images at build time along the lines of
It looks like it may be a limitation related to dynamic-import-vars, but when digging through that project I couldn't tell if the query parameters are expected to break. Based on the examples in I made sure to follow the workarounds for known limitations of the rollup plugin, like having the import starts with ReproI made a barebones repro of this at https://github.com/tonyfsullivan/sveltekit-imagetools-repro. Not sure if my use case here is just an outlier, it works flawlessly when the image file names are basic strings rather than dynamic variables. Does anyone know if this should have worked for me, or where the bug/feature request would land? At the moment I have no idea if this would be related to |
I don't know enough about svelte-kit to really debug this, but I can confirm that it is not an issue with |
I wrote a little preprocessor to make using vite-imagetools even easier. Modifiers can be directly appended to the img's src or srcset prop and the imports will be added by the preprocessor.
|
It seems that this new package will solve all the image optimization issues in an easy and efficient way: |
Steve talks about some great options with the J |
This doesn't work for SPAs though right? This requires that your site is static. |
@benmccann Would you mind sharing more of your Image component file, more particularly how you're adding different widths? |
@djmtype this PR may be of interest, planning to merge these changes from @SirNovi soon with a little documentation rdela/sveltekit-imagetools#1 (Thanks @benmccann and @eur2 for weighing in.) |
Thanks @rdela. Does that mean they'll be a drop-in Image/Picture component akin to Astro Imagetools rather than appending options as a query within the script tags? |
+1 would love to see this, mainly for automatic WebP. But image optimisations are always good to have and seems to be the biggest thing Page Speed Insights complains about. |
For folks who want to use a CDN, there's |
Great contributions above! But broken in the latest Vite Imagetools. I fixed it up for current versions and added some improvements. Instructions for others: Vite Imagetools InstructionsTested with: "@sveltejs/kit": "^1.5.0",
"vite": "^4.3.0",
"vite-imagetools": "~5.0.4",
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
+ import { imagetools } from 'vite-imagetools';
export default defineConfig({
plugins: [
+ imagetools({
+ defaultDirectives: new URLSearchParams({
+ format: 'avif;webp',
+ as: 'picture'
+ })
+ }),
sveltekit()
],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
}
});
<script>
/**
* @typedef {Object} Picture
* @property {Object} sources - The object containing different sources of image data.
* @property {Object[]} sources.avif - The array of objects containing source and width for AVIF images.
* @property {string} sources.avif[].src - The source of the AVIF image.
* @property {number} sources.avif[].w - The width of the AVIF image.
* @property {Object[]} sources.webp - The array of objects containing source and width for WebP images.
* @property {string} sources.webp[].src - The source of the WebP image.
* @property {number} sources.webp[].w - The width of the WebP image.
* @property {Object} img - The object containing the default image source.
* @property {string} img.src - The default image source.
* @property {number} img.w - The width of the default image.
* @property {number} img.h - The height of the default image.
*/
/** REQUIRED */
/** @type {Picture} */
export let src;
export let alt = '';
/** OPTIONAL */
/** @type {Boolean} */
export let draggable = false;
/** @type {'async' | 'sync' | 'auto'} */
export let decoding = 'async';
/** @type {'lazy' | 'eager'} */
export let loading = 'lazy';
let classes = '';
export { classes as class };
/** @type {number} */
export let width;
</script>
<picture>
{#each Object.entries(src.sources) as [format, images]}
<source srcset={images.map((i) => `${i.src} ${i.w}w`).join(', ')} type={'image/' + format} />
{/each}
<img
src={src.img.src}
{alt}
class={classes}
{loading}
{decoding}
{draggable}
width={src.img.w}
height={src.img.h}
/>
</picture>
<script>
import Image from '$lib/image.svelte';
import example from '$lib/assets/images/example.jpg?w=400';
</script>
<pre>
{JSON.stringify(example, null, 2)}
</pre>
<Image src={example} alt="Ocean Unsplash" /> Known limitations
|
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
part of #241 closes #9787 This adds image optimization through a new $app/images import. It's deliberately low level: The only export is getImage which you pass an image src and it returns an object containing src and srcset (possibly more?) values which you spread on an img tag. In order to use this you need to define a path to a loader in kit.config.images. The loader takes the original img src and a width and returns a URL pointing to the optimized image. You can also modify the number of sizes and trusted domains.
Thanks for testing it out and sharing the feedback. There was never such a directive in |
I'll leave this issue open for a little while longer as we consider support for image CDNs (#10323) |
@benmccann |
I think rdela/sveltekit-imagetools could probably be retired now and if there's any need for additional documentation we should try to update the official docs |
Does anyone else think having a complete example in a repo anywhere is helpful? UPDATE 2023-12-08: RETIRED |
How might this work with divs using images via |
Probably your best bet is to avoid using CSS background images if you can, and instead make a child element that is absolutely positioned and the same size as the parent, but have the "replaced content" (the actual "image" contained in the For a fixed background image covering the whole page I have this at the beginning of <script>
import Srcset from '$lib/components/image/Srcset.svelte';
</script>
<Srcset
alt=""
width="2400"
height="1500"
lazy={false}
quality={80}
draggable="false"
fetchpriority="high"
class="unselectable"
src="/images/background/vaneer.jpg"
sizes="max(100vw, calc(100vh/(1500/2400)))"
style="position: fixed; width: 100vw; height: 100vh; object-fit: cover; object-position: top center"
/>
<!--
Note: you may want to change sizes to something more like sizes="max(100vw, 100vh)" as most portrait
screens will have a DPR around 2.0 which means they will request this specified "size" times 2... and
100vh * 2 happens to be a pretty good middle ground for most mobile screens... so taking the aspect
ratio into consideration here is not so helpful as 1.0 DPR desktop devices are usually landscape... and
100vw would be a rather small image on mobile but filling 100% height would be too much when * 2...
Just want to illustrate the point that there is often more to the decision than just setting 100vw and you
will see that in Lighthouse scores saying potential savings of some KiB... For instance you may want to
take into consideration your website margins at certain breakpoints that reduce the image rendered size
to less than 100vw. [Perhaps calc(50vh/(1500/2400)) is even better; anticipating the doubling on mobile]
--> Where However, this won't work if you need a repeating background image. The best you can do then is to use image-set. You will probably want to use preload in addition if you decide to use I suppose it depends on your design requirements, but I see a lot of nice results using just CSS gradients or even canvas animations. I think the general consensus is avoid CSS backgrounds if you can, as they currently aren't very flexible and when the CSS object model is being built is not an optimal time to begin downloading images. |
I made a Image proxy that uses sharp. https://github.com/EmergencyBucket/svelte-sharp-image. It is pretty similar to NextJS's image tools. I would try to make a pr to add this to sveltekit but I'm not entirely sure how sveltekit works. |
Updated Aug 2023 by @benmccann - this thread has gotten quite long, so I've summarized some key points here. We have some docs on the site (https://kit.svelte.dev/docs/assets) that share some helpful basics. This issue discusses a potential future implementation within SvelteKit
Static optimization with an
Image
componentVite's build pipeline will handle assets that you
import
: https://vitejs.dev/guide/assets.htmlYou can use
vite-imagetools
to transform those images as part of Vite's pipeline. E.g. the most common transform might be to generate avif and webp versions of an image. You can use thedefaultDirectives
option to set a project-wide default or you can add query parameters to handle images individually. You can also import a directory of images using Vite's import.meta.glob with its query option.You could use something like bluwy/svelte-preprocess-import-assets to let users simply write
img
tags that get converted to import statements for Vite to process.A discussion of how to set this up is included at #241 (comment) and further demonstrated in #241 (comment).
Static optimization powered by a preprocessor
A problem with using an
Image
component in Svelte is that it requires the usage of:global
to style it and it's difficult to handle events on it. It's possible some of these issues could be addressed in Svelte itself (e.g. there was a community proposal regarding event forwarding sveltejs/rfcs#60), but at the current time there are no concrete plans around this.One solution to this would be to use a preprocessor to convert:
Into something like:
This actually scales very well since sveltejs/svelte#8948.
However, this approach doesn't work as well for something like the SvelteKit showcase or
import.meta.glob
because it requires the presence of animg
tag.Dynamic optimization
You could also implement a function to alter a URL and output the CDN's URL (e.g. #10323). Including this manually may become cumbersome, but as with the static optimization case, you could use something like bluwy/svelte-preprocess-import-assets to let users simply write
img
tags that get converted to use this function. The unpic library is an example of this approach. This approach works really well when users have a CDN available and some hosts like Vercel have CDNs as included offerings. For users that want to deploy to somewhere like GitHub pages the static approach might work better and so it may make sense to offer dynamic optimzation alongside one of the static optimization approaches.The text was updated successfully, but these errors were encountered: