perf: optimize PageSpeed Insights performance score (#105) (#106)

This commit implements comprehensive performance optimizations to improve
the PageSpeed Insights score from 70/100 to targeting 90+.

## Images & Assets (Est. 200+ KiB savings)
- Optimize vocalinux.png: 207KB → 44KB (79% reduction)
- Add WebP versions for all logo sizes (32, 64, 96, 192, 512px)
- Create og-image.webp: 274KB → 176KB (36% reduction)
- All WebP images provide ~92% size reduction over PNG

## JavaScript Optimization (Est. 84 KiB savings)
- Lazy load react-syntax-highlighter with next/dynamic
- Created CodeBlock component for async code highlighting
- Reduces initial bundle size by deferring heavy syntax highlighter

## Bundle Configuration
- Disable production source maps (reduces bundle size)
- Add .browserslistrc targeting modern browsers (est. 12 KiB savings)
- Remove legacy browser polyfills (IE11, old Android, etc.)

## Critical Rendering Path (Est. 300ms LCP improvement)
- Add preconnect hint for api.github.com
- Defer Google Analytics to lazyOnload strategy

## Caching Strategy
- Add cache headers configuration for static assets
- Cache-Control: public, max-age=31536000, immutable
- Applied to _next/static/* and image assets

## Accessibility Fixes
- Fix footer color contrast: text-zinc-500 → text-zinc-400
- Add prefers-reduced-motion media query support
- All animations respect user motion preferences

## Expected Impact
- Total estimated LCP reduction: ~1.5-2 seconds
- Bundle size reduction: ~100 KB
- Targeting 90+ performance score (up from 70)
This commit is contained in:
Jatin K Malik
2026-01-30 22:47:59 -08:00
committed by GitHub
parent 4219e3e398
commit 071b7b5da3
19 changed files with 134 additions and 23 deletions
+62
View File
@@ -0,0 +1,62 @@
"use client";
import React, { useState, useEffect } from "react";
import dynamic from "next/dynamic";
// Lazy load syntax highlighter to reduce initial bundle size (~84KB savings)
const SyntaxHighlighter = dynamic(
() => import("react-syntax-highlighter").then(mod => mod.default),
{
ssr: false,
loading: () => (
<div className="bg-zinc-900 rounded-lg p-4 text-sm">
<pre className="text-green-400 whitespace-pre-wrap">Loading...</pre>
</div>
),
}
);
interface CodeBlockProps {
language: string;
children: string;
className?: string;
customStyle?: React.CSSProperties;
wrapLongLines?: boolean;
}
export function CodeBlock({
language,
children,
className = "",
customStyle,
wrapLongLines = false,
}: CodeBlockProps) {
const [style, setStyle] = useState<any>(null);
useEffect(() => {
// Lazy load the style
import("react-syntax-highlighter/dist/esm/styles/hljs").then(mod => {
setStyle(mod.atomOneDark);
});
}, []);
if (!style) {
return (
<div className={`bg-zinc-900 rounded-lg p-4 text-sm ${className}`} style={customStyle}>
<pre className="text-green-400 whitespace-pre-wrap">{children}</pre>
</div>
);
}
return (
<SyntaxHighlighter
language={language}
style={style}
className={className}
customStyle={customStyle}
wrapLongLines={wrapLongLines}
>
{children}
</SyntaxHighlighter>
);
}