Image Optimization
Automatic image optimization with WebP/AVIF support, lazy loading, responsive images, and remote image support.
Introduction
Loly Framework includes a complete image optimization system similar to Next.js Image, with support for local and remote images, automatic format conversion, lazy loading, and more.
Important: Always use the Image component from @lolyjs/core/components, never from Next.js. Loly Framework has its own optimized image system that provides all the features you need.
Features
- Automatic optimization - Resizing, compression, and format conversion
- Modern formats - Support for WebP and AVIF
- Remote images - Support for images from external domains (with whitelist)
- Lazy loading - Deferred loading by default
- Responsive images - Automatic srcset generation
- Smart cache - Disk cache for better performance
- CLS prevention - Aspect ratio containers to avoid layout shift
Basic Usage
Local Image
import { Image } from "@lolyjs/core/components";
export default function MyPage() {
return (
<Image
src="/assets/hero.jpg"
alt="Hero image"
width={800}
height={600}
/>
);
}Remote Image
Remote images require configuration in loly.config.ts. See the Remote Images section below.
import { Image } from "@lolyjs/core/components";
<Image
src="https://example.com/image.jpg"
alt="Remote image"
width={1200}
height={800}
/>Configuration
Configure image optimization settings in loly.config.ts:
import type { FrameworkConfig } from "@lolyjs/core";
export default {
images: {
// Device sizes for srcset generation
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
// Image sizes for srcset
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
// Supported formats
formats: ["image/webp", "image/avif"],
// Default quality (1-100)
quality: 75,
// Minimum cache TTL in seconds
minimumCacheTTL: 60,
// Allow SVG (security risk if enabled)
dangerouslyAllowSVG: false,
// Content Security Policy for SVG
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
// Maximum sizes
maxWidth: 3840,
maxHeight: 3840,
},
} satisfies Partial<FrameworkConfig>;Remote Images
To use remote images, you must configure allowed domains in loly.config.ts:
import type { FrameworkConfig } from "@lolyjs/core";
export default {
images: {
// Option 1: Use remotePatterns (recommended)
remotePatterns: [
{
protocol: "https",
hostname: "images.unsplash.com",
},
{
protocol: "https",
hostname: "**.unsplash.com", // Wildcard for subdomains
pathname: "/photos/**", // Optional: restrict path
},
],
// Option 2: Use domains (legacy, Next.js style)
// domains: ['images.unsplash.com', 'cdn.example.com'],
},
} satisfies Partial<FrameworkConfig>;Security: All remote domains must be whitelisted. If you try to use an image from a non-allowed domain, you will get a 403 error.
Image Component Props
Basic Props
interface ImageProps {
src: string; // Image path (local or remote)
alt: string; // Alternative text (required)
width?: number; // Width in pixels
height?: number; // Height in pixels
className?: string; // CSS classes
}Optimization Props
{
quality?: number; // Quality (1-100, default: 75)
format?: 'webp' | 'avif' | 'jpeg' | 'png' | 'auto'; // Forced format
priority?: boolean; // Load immediately (disables lazy loading)
fill?: boolean; // Fill mode (fills parent container)
sizes?: string; // Sizes attribute for responsive images
placeholder?: 'blur' | 'empty'; // Placeholder type
blurDataURL?: string; // Blur placeholder URL
}Examples
Image with Custom Quality
<Image
src="/assets/photo.jpg"
alt="Photo"
width={800}
height={600}
quality={90} // High quality
/>Responsive Image
The component automatically generates a srcset with different sizes based on configured deviceSizes.
<Image
src="/assets/hero.jpg"
alt="Hero"
width={1920}
height={1080}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 1920px"
/>Priority Loading
<Image
src="/assets/logo.png"
alt="Logo"
width={200}
height={100}
priority // Loads immediately (above-the-fold)
/>Fill Mode
<div className="relative h-64 w-full">
<Image
src="/assets/background.jpg"
alt="Background"
fill // Fills parent container
className="object-cover"
/>
</div>Remote Image with Format Conversion
<Image
src="https://images.unsplash.com/photo-123"
alt="Unsplash photo"
width={1200}
height={800}
format="webp" // Automatically converts to WebP
quality={85}
/>Lazy Loading (Default)
Lazy loading is enabled by default. Images load when scrolled into view.
// Lazy loading is enabled by default
<Image
src="/assets/image.jpg"
alt="Image"
width={600}
height={400}
// No priority = automatic lazy loading
/>Complete Example
import { Image } from "@lolyjs/core/components";
export default function Gallery() {
const images = [
{ id: 1, url: "/assets/img1.jpg", alt: "Image 1" },
{ id: 2, url: "/assets/img2.jpg", alt: "Image 2" },
{ id: 3, url: "/assets/img3.jpg", alt: "Image 3" },
];
return (
<div className="grid grid-cols-3 gap-4">
{images.map((img) => (
<Image
key={img.id}
src={img.url}
alt={img.alt}
width={400}
height={300}
quality={80}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 400px"
className="rounded-lg"
/>
))}
</div>
);
}Optimization Endpoint
The framework exposes an internal endpoint /_loly/image that processes images:
/_loly/image?src=/path/to/image.jpg&w=800&h=600&q=75&format=webpEndpoint Parameters
src- Image path (required)w- Width in pixels (optional)h- Height in pixels (optional)q- Quality (1-100, optional)format- Output format:webp,avif,jpeg,png,auto(optional)fit- Fit mode:contain,cover,fill,inside,outside(optional)
Cache
Optimized images are automatically cached in .loly/cache/images/. The cache is based on:
- Image URL
- Dimensions (width/height)
- Quality
- Format
This means the same image with the same parameters is only processed once.
Security
Remote Domain Validation
For security, all remote domains must be whitelisted. If you try to use an image from a non-allowed domain, you will get a 403 error.
// ✅ Allowed (configured in loly.config.ts)
<Image src="https://images.unsplash.com/photo.jpg" ... />
// ❌ Blocked (domain not allowed)
<Image src="https://malicious-site.com/image.jpg" ... />SVG
By default, SVG images are disabled for security reasons. To enable them:
images: {
dangerouslyAllowSVG: true,
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
}Best Practices
1. Always Provide width and height
// ✅ Correct - prevents CLS
<Image src="/photo.jpg" alt="Photo" width={800} height={600} />
// ❌ Incorrect - can cause layout shift
<Image src="/photo.jpg" alt="Photo" />2. Use priority for Above-the-Fold
// ✅ Hero image loads immediately
<Image src="/hero.jpg" alt="Hero" width={1920} height={1080} priority />
// ✅ Images further down use lazy loading
<Image src="/gallery-1.jpg" alt="Gallery" width={400} height={300} />3. Configure sizes for Responsive Images
<Image
src="/hero.jpg"
alt="Hero"
width={1920}
height={1080}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 1920px"
/>4. Use Modern Formats
The framework automatically converts to WebP or AVIF if enabled in configuration. This can reduce file size by 50-70%.
5. Adjust Quality Based on Use Case
// High quality for important photos
<Image src="/hero.jpg" quality={90} ... />
// Medium quality for thumbnails
<Image src="/thumb.jpg" quality={60} ... />Troubleshooting
Error: "Remote image domain not allowed"
Problem: You're trying to use an image from a non-configured domain.
Solution: Add the domain to remotePatterns or domains in loly.config.ts:
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'your-domain.com' }
]
}Error: "Image not found"
Problem: The local image doesn't exist at the specified path.
Solution: Verify that the image is in the public/ directory and the path is correct:
// ✅ Correct - image in public/assets/logo.png
<Image src="/assets/logo.png" ... />
// ❌ Incorrect - wrong path
<Image src="/logo.png" ... />Images are not optimized
Problem: Images are served directly without optimization.
Solution: Make sure you're using the Image component from @lolyjs/core/components, not a regular HTML <img> tag.
SVG doesn't work
Problem: SVG images are not processed.
Solution: Enable SVG in configuration (with caution):
images: {
dangerouslyAllowSVG: true,
}Performance
The image optimization system can significantly improve performance:
- Size reduction: 50-70% smaller with WebP/AVIF
- Load time: 30-50% faster
- Improved LCP: 20-40% improvement
- Reduced CLS: 30-50% less layout shift