As developers, we often talk about performance, but how often do we actually implement it properly? Today, I'm sharing a few specific optimizations I made to help reduce initial page load time.
The Challenge
My portfolio site was functional, but every time I loaded the work page with all my projects, I noticed a slight lag. Images took their time to appear, and the initial JavaScript bundle felt heavier than necessary.
1. Infinite Scroll Pagination: Less is More
The Problem: Loading 20+ projects at once was overkill. Most visitors wouldn't scroll through everything, yet they paid the cost upfront.
The Solution: I implemented infinite scroll with the Intersection Observer API. Now, the page loads just 6 projects initially, then seamlessly loads more as you scroll.
const loadMore = () => {
if (loading.value || !hasMore.value) return;
loading.value = true;
const start = currentPage.value * ITEMS_PER_PAGE;
const end = start + ITEMS_PER_PAGE;
const newProjects = allProjects.value?.slice(start, end) || [];
visibleProjects.value.push(...newProjects);
currentPage.value++;
loading.value = false;
};
2. Smart Component Loading
Instead of bundling all components together, I implemented code splitting for components that aren't immediately needed:
// Before: Eager loading
import GithubOutline from '~/components/svg/icons/GithubOutline';
// After: Lazy loading
const GithubOutline = defineAsyncComponent(
() => import('~/components/svg/icons/GithubOutline')
);
These icon components now only load when they're actually rendered, shaving precious kilobytes off the initial bundle.
3. Image Optimization: The Modern Way
Modern image formats like WebP and AVIF offer significantly better compression than traditional formats. I configured Nuxt Image to automatically convert and optimize all images:
image: {
formats: ['webp', 'avif'],
quality: 80,
screens: {
xs: 320,
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
xxl: 1536
}
}
Combined with lazy loading (loading="lazy"
), images now only load when they're about to enter the viewport.
4. Resource Hints: Being Proactive
Why wait for the browser to discover external resources when you can tell it ahead of time?
// Preload critical fonts
{
rel: 'preload',
as: 'font',
type: 'font/woff2',
href: '/assets/fonts/Circular/circular-book.woff2',
crossorigin: 'anonymous'
}
// Preconnect to external domains
{
rel: 'preconnect',
href: 'https://cdn.sanity.io',
crossorigin: 'anonymous'
}
These hints establish early connections to my CMS and analytics services, reducing latency when they're actually needed.
5. DNS Prefetch for Third-Party Services
For services that aren't critical to the initial render, DNS prefetch does the DNS resolution early without establishing a full connection:
{
rel: 'dns-prefetch',
href: 'https://cdn.sanity.io'
}
This strikes a perfect balance—preparing for future requests without adding overhead to the initial page load.
Have you implemented similar optimizations? I'd love to hear what worked (or didn't work) for you. Drop me a message on LinkedIn.