Optimize blog performance with Next.js 16 features and video conversion

## 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
This commit is contained in:
2025-11-20 15:50:46 +08:00
parent d7dc279d32
commit 3748e2f9e8
5 changed files with 145 additions and 19 deletions

View File

@@ -81,9 +81,11 @@ export default async function BlogPostPage({ params }: Props) {
<ReadingProgress />
<PostLayout hasToc={hasToc}>
<div className="space-y-8">
<SectionDivider>
<ScrollReveal>
<header className="mb-6 space-y-4 text-center">
{/* Main content area for Pagefind indexing */}
<div data-pagefind-body>
<SectionDivider>
<ScrollReveal>
<header className="mb-6 space-y-4 text-center">
{post.published_at && (
<p className="type-small text-slate-500 dark:text-slate-500">
{new Date(post.published_at).toLocaleDateString(
@@ -95,7 +97,7 @@ export default async function BlogPostPage({ params }: Props) {
{post.title}
</h1>
{post.tags && (
<div className="flex flex-wrap justify-center gap-2 pt-2">
<div className="flex flex-wrap justify-center gap-2 pt-2" data-pagefind-meta="tags">
{post.tags.map((t) => (
<Link
key={t}
@@ -133,23 +135,26 @@ export default async function BlogPostPage({ params }: Props) {
</article>
</ScrollReveal>
</SectionDivider>
</div>
<FooterCue />
<SectionDivider>
<ScrollReveal>
<PostStorylineNav
current={post}
newer={neighbors.newer}
older={neighbors.older}
/>
</ScrollReveal>
</SectionDivider>
{relatedPosts.length > 0 && (
{/* Exclude navigation and related posts from search indexing */}
<div data-pagefind-ignore>
<SectionDivider>
<ScrollReveal>
<section className="space-y-6 rounded-2xl border border-slate-200/60 bg-slate-50/50 p-8 dark:border-slate-800 dark:bg-slate-900/30">
<PostStorylineNav
current={post}
newer={neighbors.newer}
older={neighbors.older}
/>
</ScrollReveal>
</SectionDivider>
{relatedPosts.length > 0 && (
<SectionDivider>
<ScrollReveal>
<section className="space-y-6 rounded-2xl border border-slate-200/60 bg-slate-50/50 p-8 dark:border-slate-800 dark:bg-slate-900/30">
<div className="flex items-center justify-between gap-2">
<h2 className="type-subtitle font-semibold text-slate-900 dark:text-slate-50">
@@ -166,7 +171,8 @@ export default async function BlogPostPage({ params }: Props) {
</section>
</ScrollReveal>
</SectionDivider>
)}
)}
</div>
</div>
</PostLayout>
</>