## Performance Improvements ### Next.js 16 Features - Enable Partial Prerendering (PPR) via cacheComponents - Add Turbopack for 4-5x faster development builds - Implement loading states and error boundaries - Configure static asset caching (1 year max-age) ### Bundle Size Reduction - Replace Framer Motion with CSS-only animations (~50KB reduction) - Dynamic import for SearchModal component (lazy loaded) - Optimize scroll reveals using IntersectionObserver - Remove loading attribute from OptimizedVideo (not supported on video elements) ### Image & Video Optimization - Add responsive sizes attributes to all Image components - Implement lazy loading for below-fold images - Add priority loading for hero images - Convert large GIFs to MP4/WebM formats (80-95% file size reduction) - Create OptimizedVideo component for efficient video playback ### Search Optimization - Configure Pagefind to index only essential content - Add data-pagefind-body wrapper for main content - Add data-pagefind-meta for tags metadata - Add data-pagefind-ignore for navigation and related posts - Result: Cleaner search results, smaller index size ### SEO & Social Media - Add dynamic OG image generation using @vercel/og - Enhance metadata with OpenGraph and Twitter Cards - Generate 1200x630 social images for all posts ### Documentation - Update README with comprehensive performance optimizations section - Document Pagefind configuration - Add GIF to video conversion details ## Technical Details Video file size reduction: - AddNewThings3.gif (2.4MB) → WebM (116KB) = 95% reduction - Things3.gif (1.5MB) → WebM (170KB) = 89% reduction - Total: 3.9MB → 286KB = 93% reduction Build output: 49 pages indexed, 5370 words searchable
69 lines
1.7 KiB
TypeScript
69 lines
1.7 KiB
TypeScript
import { HTMLAttributes } from 'react';
|
|
import clsx from 'clsx';
|
|
|
|
interface OptimizedVideoProps extends Omit<HTMLAttributes<HTMLVideoElement>, 'src'> {
|
|
src: string;
|
|
alt?: string;
|
|
width?: number;
|
|
height?: number;
|
|
autoPlay?: boolean;
|
|
loop?: boolean;
|
|
muted?: boolean;
|
|
playsInline?: boolean;
|
|
controls?: boolean;
|
|
poster?: string;
|
|
}
|
|
|
|
/**
|
|
* Optimized video component that provides:
|
|
* - Multiple format support (WebM and MP4) for better browser compatibility
|
|
* - Proper accessibility attributes
|
|
* - Automatic GIF-like behavior when autoPlay is enabled
|
|
* - Lightweight alternative to GIF files with 80-95% file size reduction
|
|
*/
|
|
export function OptimizedVideo({
|
|
src,
|
|
alt,
|
|
width,
|
|
height,
|
|
autoPlay = true,
|
|
loop = true,
|
|
muted = true,
|
|
playsInline = true,
|
|
controls = false,
|
|
poster,
|
|
className,
|
|
...props
|
|
}: OptimizedVideoProps) {
|
|
// Remove file extension to get base path
|
|
const basePath = src.replace(/\.(mp4|webm|gif)$/i, '');
|
|
|
|
return (
|
|
<video
|
|
width={width}
|
|
height={height}
|
|
autoPlay={autoPlay}
|
|
loop={loop}
|
|
muted={muted}
|
|
playsInline={playsInline}
|
|
controls={controls}
|
|
poster={poster}
|
|
className={clsx('inline-block', className)}
|
|
aria-label={alt}
|
|
{...props}
|
|
>
|
|
{/* WebM for better compression (Chrome, Firefox, Edge) */}
|
|
<source src={`${basePath}.webm`} type="video/webm" />
|
|
|
|
{/* MP4 for Safari and older browsers */}
|
|
<source src={`${basePath}.mp4`} type="video/mp4" />
|
|
|
|
{/* Fallback message for browsers that don't support video */}
|
|
<p className="text-slate-500 dark:text-slate-400">
|
|
Your browser does not support the video tag.
|
|
{alt && <span className="block mt-2">{alt}</span>}
|
|
</p>
|
|
</video>
|
|
);
|
|
}
|