Skip to content
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

feat: add experimental @sveltejs/image package #9787

Closed
wants to merge 67 commits into from

Conversation

dummdidumm
Copy link
Member

@dummdidumm dummdidumm commented Apr 27, 2023

See the readme for more info. This is a experimental for now.

Possible follow-ups:

  • support Vite aliases in the preprocessor
  • should dynamic component upscaling be removed? (comment)
  • remove or use height in providers (cloudflare, netlify, vercel)
  • fix bug in vite-imagetools so that images that end up the same get filtered out as duplicates and then enable &w=
  • document how to handle which images get cached on a CDN. should vite's build process be involved to hash image names for uniqueness?
  • document how this interacts with SvelteKit's paths.assets config
  • document an example of import.meta.glob (example in vite-imagetools)
  • make format, device_sizes, etc. configurable
  • document advanced custom vite-imagetools usage probably by creating own instance of it and disabling the built-in one
  • document how to have some images statically optimized and some dynamically optimized by leveraging the previous item and the include/exlude options of vite-imagetools
  • art direction
  • cache statically optimized images
  • use in new projects in create-svelte and move docs from readme to site
  • potential new features like mdsvex, lqip, and additional CDNs (could create thin wrappers around unpic or update API to match)
  • changes in Svelte to allow styling without :global (Passing class to components svelte#2870 (comment))
  • legacy fallback support. right now only webp/avif are generated, but won't work in IE or Safari 13 and older

Related to #241

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

@changeset-bot
Copy link

changeset-bot bot commented Apr 27, 2023

🦋 Changeset detected

Latest commit: 6bca660

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/image Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

packages/image/README.md Show resolved Hide resolved
packages/image/README.md Outdated Show resolved Hide resolved
packages/image/package.json Outdated Show resolved Hide resolved
sites/kit.svelte.dev/vite.config.js Outdated Show resolved Hide resolved
packages/image/src/vite-plugin.js Outdated Show resolved Hide resolved
// TODO make these configurable from the outside

/**
* @param {PluginOptions['runtime']} [_options]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the build-time tool using runtime options?

@buhodev
Copy link

buhodev commented May 28, 2023

is there any update on this?

@Rich-Harris
Copy link
Member

is there any update on this?

We decided that this isn't the right approach — we have an idea for a solution that we do like, but haven't made any progress towards implementation yet.

Essentially there are two almost completely unrelated problems to solve:

  1. Optimizing images dynamically, i.e. routing image requests to an image CDN
  2. Generating optimal images at build time

Neither of these actually benefits from a component. In the first case, you just need some logic for generating the src, which is just a function. For example, to use Vercel image optimization in a recent project, I added this function...

import { dev } from '$app/environment';

export function optimize(src: string, widths = [640, 960, 1280], quality = 90) {
  if (dev) return src;

  return widths
    .slice()
    .sort((a, b) => a - b)
    .map((width, i) => {
      const url = `/_vercel/image?url=${encodeURIComponent(src)}&w=${width}&q=${quality}`;
      const descriptor = i < widths.length - 1 ? ` ${width}w` : '';
      return url + descriptor;
    })
    .join(', ');
}

...which gets used like this:

<img
  class="absolute left-0 top-0 w-full h-full"
  srcset={optimize(photo.url)}
  alt={photo.description}
/>

For the second case, where we have the asset at build time and can generate multiple optimized variants (with immutably cacheable URLs) and add width and height attributes to avoid layout shift, we need to use a preprocessor to find the asset in some markup like this...

<img alt="a potato" src="./potato.jpg">

...so that a Vite plugin can do its work. Again, there's no real value in involving a component — if we need a preprocessor anyway, then we can get that preprocessor to replace any <img> elements that statically reference a relative source with optimal markup (using <picture> and srcset if appropriate, etc):

<script>
  import __image_1 from './potato.jpg';
</script>

<img alt="a potato" src={__image_1} width="640" height="360">

There's a bunch of details to figure out here and it won't happen overnight, but we think it'll be really nice to work with.

dummdidumm added a commit that referenced this pull request Jul 5, 2023
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.
@dummdidumm
Copy link
Member Author

Closing as outdated - static images are done through @sveltejs/enhanced-img, dynamic images TBD

@dummdidumm dummdidumm closed this Dec 13, 2023
@dummdidumm dummdidumm deleted the image-experiments branch December 13, 2023 09:05
@leoj3n
Copy link
Contributor

leoj3n commented Jan 16, 2024

Here is a detailed guide based on the Rich Harris answer above regarding optimized images on Vercel...

https://github.com/leoj3n/svelte-vercel-optimized-images

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants