frontendnuxt

Optimizing Assets for Maximum Web Performance

The worst performance culprits? Unoptimized images, bloated JavaScript bundles, and poor asset loading. Here's what actually makes a difference.

·5 min read

I've spent years chasing down performance bottlenecks. The worst culprits? Unoptimized images, bloated JavaScript bundles, and poor asset loading strategies. Let me show you what actually moves the needle when it comes to web performance.

Minify and Compress Everything

This sounds basic, but you'd be surprised how many projects ship unminified assets to production.

JavaScript and CSS Minification

I use Terser for JavaScript and CSSNano for CSS in every build pipeline. These tools strip out whitespace, comments, and unnecessary characters. The result? Smaller files that download and parse faster.

Set up Terser in your Webpack config once and forget about it. Same with CSSNano in PostCSS. Automate this - don't rely on remembering to minify before each deploy.

Image Compression - The Low-Hanging Fruit

Images are usually the biggest performance killer on a site. I learned this the hard way when a client complained their site was slow, and I found 5MB product photos on every page. Oops.

Now I compress everything:

  • TinyPNG for PNGs and JPEGs - crazy good compression with minimal quality loss
  • ImageOptim if I'm batch processing locally
  • Better yet, convert to WebP format for even smaller files

Automate this in your build process with imagemin. Your users on mobile networks will thank you.

Code Splitting - Don't Ship What Users Don't Need

Why make users download your entire JavaScript bundle when they only need 20% of it on the current page?

Webpack's code splitting lets you break large bundles into smaller chunks that load on demand. I typically split on routes - the homepage doesn't need the admin panel code.

// Dynamic imports load code only when needed
const AdminPanel = () => import('./components/AdminPanel.vue')

This single change cut my initial JavaScript bundle size in half on one project. Users got a usable page much faster.

The same goes for CSS - load only what's needed for each component. Vue's scoped styles and CSS Modules make this easy. No more shipping one giant stylesheet for your entire site.

HTTP/2 Server Push - For Critical Resources Only

HTTP/2 lets you push critical resources like fonts or above-the-fold CSS before the browser even asks for them. When used right, this eliminates round trips and speeds up initial renders.

But don't abuse it. I once pushed everything and made performance worse. Only push truly critical resources that you know the page needs immediately.

Configure this at the server level (Nginx or Apache). Push your main CSS and primary fonts, maybe critical JavaScript. That's it.

Lazy Loading - Load It When You Need It

Why load an image that's three screens below the fold? You shouldn't.

Defer Non-Critical JavaScript

Use defer or async attributes on script tags:

  • async for independent scripts (analytics, third-party widgets)
  • defer for scripts that depend on the DOM being parsed

This keeps scripts from blocking page rendering, which means users see content faster.

Lazy Load Images and Videos

Modern browsers support loading="lazy" natively:

<img src="large-image.jpg" loading="lazy" alt="Description" />

This delays loading until the image is near the viewport. It's built into React, Vue, and most modern frameworks. Use it.

Modern File Formats - WebP and SVG

WebP Images

WebP provides better compression than JPEG or PNG without quality loss. I convert all project images to WebP now. Tools like Squoosh make this dead simple.

Most browsers support WebP these days, and you can provide fallbacks for older browsers if needed.

SVG for Icons

SVG files are tiny, scale perfectly, and look sharp on any display. I use them for all icons and logos. You can inline them directly in HTML or use an SVG sprite for multiple icons.

Stop using icon fonts. SVGs are lighter, more accessible, and don't have the flash-of-unstyled-content issues.

Font Optimization

Fonts can easily add hundreds of kilobytes to your page weight.

Subset Your Fonts

Most font files include characters you'll never use. Font Squirrel's Webfont Generator lets you subset fonts to include only the characters you need. Latin-only? Drop everything else.

Use font-display: swap

@font-face {
  font-family: 'CustomFont';
  src: url('font.woff2') format('woff2');
  font-display: swap;
}

This shows system fonts immediately while custom fonts load in the background. Users see text right away instead of staring at blank space (FOIT - Flash of Invisible Text).

Google Fonts includes this by default, but if you're self-hosting, set it manually.

What Actually Matters

After optimizing dozens of sites, here's what I focus on first:

  1. Image optimization - Convert to WebP, compress aggressively
  2. Code splitting - Load only what's needed for the current route
  3. Lazy loading - Defer offscreen images and non-critical scripts
  4. Font optimization - Subset fonts and use font-display: swap

You don't need to implement everything at once. Start with images - they're usually the biggest win for the least effort. Then tackle code splitting and lazy loading.

The goal isn't a perfect score on Lighthouse. It's giving users a fast, smooth experience. Every millisecond matters when someone's on a slow connection or older device.