AvalonAvalon
GitHub

Image Optimization

Automatic image optimization with responsive srcset generation, modern formats, and lazy loading.

Avalon includes built-in image optimization powered by vite-imagetools. Images are automatically converted to modern formats, resized for responsive layouts, and optimized for performance.

Features

  • Modern formats - Automatic WebP/AVIF conversion
  • Responsive srcset - Generate multiple sizes for different viewports
  • Lazy loading - Images load on-demand by default
  • Metadata stripping - Remove EXIF data for privacy
  • Zero runtime - All optimization happens at build time

The Image Component

Avalon provides an Image component that handles all the complexity for you:

import { Image } from '@useavalon/avalon/client';
import hero from './hero.jpg?w=400;800;1200&format=webp&as=srcset';

export function Hero() {
  return (
    <Image
      src={hero}
      sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
      alt="Hero image"
    />
  );
}

The component automatically:

  • Sets loading="lazy" and decoding="async" for performance
  • Detects srcset strings and extracts a fallback src
  • Handles both single URLs and responsive srcsets

Basic Usage

Single Optimized Image

import { Image } from '@useavalon/avalon/client';
import thumbnail from './photo.png?w=200&format=webp';

export function Card() {
  return <Image src={thumbnail} alt="Thumbnail" width={200} />;
}

Responsive Images with srcset

For responsive images, use multiple widths with &as=srcset:

import { Image } from '@useavalon/avalon/client';
import hero from './hero.jpg?w=400;800;1200&format=webp&as=srcset';

export function Hero() {
  return (
    <Image
      src={hero}
      sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
      alt="Hero image"
    />
  );
}

This generates a srcset like:

/@imagetools/abc123 400w, /@imagetools/def456 800w, /@imagetools/ghi789 1200w

Available Directives

Size

DirectiveExampleDescription
w?w=800Set width in pixels
h?h=600Set height in pixels
w (multiple)?w=400;800;1200Generate multiple sizes

Format

DirectiveExampleDescription
format?format=webpConvert to format (webp, avif, jpg, png)
quality?quality=80Set quality (1-100)

Output

DirectiveExampleDescription
as=srcset?w=400;800&as=srcsetReturn srcset string
as=metadata?as=metadataReturn image metadata object

Image Component Props

PropTypeDefaultDescription
srcstringrequiredImage URL or srcset string
altstringrequiredAlt text for accessibility
sizesstring-Sizes attribute for srcset
loading'lazy' | 'eager''lazy'Loading strategy
decoding'async' | 'sync' | 'auto''async'Decoding hint
widthnumber | string-Image width
heightnumber | string-Image height
classNamestring-CSS class
styleobject-Inline styles

Configuration

Image optimization is enabled by default. Customize it in your Vite config:

// vite.config.ts
import { avalon } from '@useavalon/avalon';

export default defineConfig({
  plugins: [
    avalon({
      image: {
        // Default format for optimized images
        defaultFormat: 'webp', // 'webp' | 'avif' | 'jpg' | 'png'
        
        // Default quality (1-100)
        quality: 80,
        
        // Breakpoint widths for srcset
        widths: [200, 400, 600, 800, 1200],
        
        // Strip EXIF metadata
        removeMetadata: true,
      },
    }),
  ],
});

Disabling Image Optimization

avalon({
  image: false, // Disable entirely
})

TypeScript Support

Add the image type declarations to your tsconfig.json:

{
  "include": [
    "node_modules/@useavalon/avalon/src/types/image.d.ts"
  ]
}

Best Practices

  1. Use the Image component - It handles srcset detection and sets performance defaults
  2. Use WebP - Widely supported with great compression
  3. Specify sizes - Always include the sizes attribute with srcset
  4. Set dimensions - Include width and height to prevent layout shift
  5. Use appropriate widths - Match your breakpoints (e.g., 400, 800, 1200)

Example: Full Responsive Image

import { Image } from '@useavalon/avalon/client';
import hero from './hero.jpg?w=400;800;1200;1920&format=webp&as=srcset';

export function HeroSection() {
  return (
    <Image
      src={hero}
      sizes="(max-width: 400px) 400px, (max-width: 800px) 800px, (max-width: 1200px) 1200px, 1920px"
      alt="Hero"
      width={1920}
      height={1080}
      loading="eager" // Above the fold - load immediately
      style={{ width: '100%', height: 'auto' }}
    />
  );
}