File Optimization Still Matters in Astro Projects

Date
Clock 8 min read
Tag
#astro#web-performance#vite#image-optimization
File Optimization Still Matters in Astro Projects

Even a well configured project can still be slow

In the previous article I focused on navigation speed, using Prefetching, ClientRouter and Resource hints.

Those techniques make navigation feel faster. They reduce waiting during user interaction.

But they do not solve another problem.

File weight.

A project can still ship large HTML files, bloated CSS, heavy images, and unnecessary JavaScript.

No routing trick will fix that.

The second layer of performance work happens during the build process and asset design.

That is where file optimization becomes critical. This article explains the main techniques used in the project.


Build time optimization in Astro

Astro performs most optimizations during build.

Two tools handle most of the work in this project.

  • Vite build optimizations
  • astro-compress

Both run automatically duringastro build.

The configuration looks like this.

export default defineConfig({ integrations: [ compress({ CSS: true, HTML: { "html-minifier-terser": { collapseWhitespace: true, removeComments: true, ignoreCustomFragments: [ /<pre[\s\S]*?<\/pre>/, /<code[\s\S]*?<\/code>/, /<kbd[\s\S]*?<\/kbd>/, ], }, }, JavaScript: true, Image: false, }), ], vite: { build: { minify: "esbuild", cssMinify: true, assetsInlineLimit: 8192, }, }, });

Each tool solves a different part of the problem.


Vite minification during the build

Astro uses Vite as its underlying build system.

During the build step Vite performs several optimizations automatically.

vite: { build: { minify: "esbuild", cssMinify: true, assetsInlineLimit: 8192, } }

These options control how JavaScript, CSS, and assets are processed.

JavaScript minification

The setting

minify: "esbuild";

runs the esbuild minifier during compilation.

The minifier performs several transformations.

  • removes whitespace
  • shortens variable names
  • removes unused code
  • compresses syntax

Example transformation.

Before build

function calculateTotal(price, tax) { const total = price + price * tax; return total; }

After minification

function t(e, r) { return e + e * r; }

The browser downloads less code and parses it faster.


CSS minification

cssMinify: true;

removes whitespace, comments, and redundant rules from stylesheets.

Example.

Before

.card { padding: 16px; background: white; }

After

.card { padding: 16px; background: white; }

Small change individually.

Huge impact across a large stylesheet.


Asset inlining

assetsInlineLimit: 8192;

Small assets under 8kb are converted into base64 strings and embedded directly inside the bundle.

Instead of downloading many tiny files, the browser loads them with the main bundle.

This reduces HTTP requests.


Astro-compress

Vite handles JavaScript and CSS.

astro-compressfocuses on HTML output and final asset compression.

Integration is straightforward.

import compress from "astro-compress"; integrations: [ compress({ CSS: true, JavaScript: true, HTML: { "html-minifier-terser": { collapseWhitespace: true, removeComments: true, }, }, }), ];

It performs several tasks.

  • HTML minification
  • CSS compression
  • JavaScript compression
  • optional image compression

The goal is simple.

Ship the smallest possible files to the browser.


Protecting code blocks with ignoreCustomFragments

One detail required special handling.

HTML minifiers aggressively collapse whitespace.

That breaks code blocks.

Indentation disappears and formatted code becomes unreadable.

The project avoids that usingignoreCustomFragments.

ignoreCustomFragments: [ /<pre[\s\S]*?<\/pre>/, /<code[\s\S]*?<\/code>/, /<kbd[\s\S]*?<\/kbd>/, ];

This tells the minifier to skip specific HTML fragments.

Lifecycle of the HTML minifier.

Generated HTML Minifier scans document Matches ignored fragments Skips formatting inside code blocks Minifies everything else

The result.

  • Clean HTML output
  • Preserved code formatting

Which matters a lot on a technical blog.


Why SVG icons are embedded directly in HTML

Icons across the site use SVG.

Instead of loading them as external images, they are rendered inline.

Example usage.

<SVGIcon icon={skill_icon} class="h-20 w-20" />

Embedding SVGs directly provides several advantages.

1. No network requests

External images require additional HTTP requests.

Inline SVG becomes part of the HTML document.

HTML Download SVG already available

No extra request.


2. Perfect scalability

SVG uses vector paths.

That means it scales without losing quality.

Small icon → large icon → same sharpness

Raster formats like PNG or JPG cannot do that.


3. CSS styling

Inline SVG can be styled with CSS.

Example.

svg { stroke: currentColor; }

Icons automatically adapt to themes and colors.


Image optimization with Astro assets

Large images can easily dominate page weight.

Astro provides an excellent tool for this through astro:assets.

Two helpers appear often in the project.

  • getImage
  • Picture

Example from the hero component.

const mobileImg = await getImage({ src: backgroundImage, width: 800, height: 1200, format: "webp", quality: 70, });

This generates a pre optimized image during build.

Then the<picture>element chooses the correct version.

<picture> <source media="(max-width: 767px)" srcset={mobileImg.src} /> <source media="(min-width: 768px)" srcset={desktopImg.src} /> <img src={desktopImg.src} /> </picture>

Lifecycle of responsive image loading.

Page loads Browser evaluates media queries Correct image selected Only required resolution downloaded

No wasted bandwidth.


The Picture component for content images

For regular UI images the project uses Astro’sPicturecomponent.

Example from a card component.

<Picture src={image} widths={[250, 500, 800]} formats={["webp"]} sizes="(max-width: 480px) 250px, (max-width: 768px) 400px" />

Astro generates multiple image versions.

250px image 500px image 800px image

The browser picks the right one depending on screen size.

That keeps images crisp while avoiding oversized downloads.


CSS splitting strategy

CSS structure also affects performance.

The project uses a simple rule.

Global styles for layout and base rules.
Component styles for specific features.

Example.

styles/ global.css mockup-code.css glass.css

Components import their own styles when needed.

import "@styles/glass.css";

This keeps styling modular.


How Astro bundles CSS and JavaScript

Astro performs automatic page level bundling.

Every page only ships the CSS and JavaScript required for its components.

Build pipeline.

Page imports components Astro analyzes dependencies Extracts required CSS and JS Creates optimized bundle for that page

If a component only appears on one page, its styles are not loaded anywhere else.


Global and local assets working together

The final architecture uses two layers.

Global assets

Loaded everywhere.

Examples.

  • global CSS
  • fonts
  • layout scripts
  • navigation styles

These are stable and reused across the site.


Local assets

Loaded only when needed.

Examples.

  • component CSS
  • feature scripts
  • page specific styles

Astro merges them during the build.

Global CSS Component CSS Page bundle

The browser receives a single optimized bundle for the page being visited.

That avoids unused styles and unnecessary JavaScript.


Why these optimizations matter

Modern frameworks often hide build complexity.

That is good for developer experience. But performance still depends on what the build produces.

This project focuses on three principles.

  • Minify everything that can be minified
  • Avoid unnecessary downloads
  • Only ship code required for each page

Navigation optimizations make the site feel fast. File optimization ensures the browser has less work to do in the first place.

Both layers together create the performance profile of the site.