Even a well configured project can still be slow Copied!
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 Copied!
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 Copied!
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 Copied!
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 Copied!
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 Copied!
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 Copied!
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 Copied!
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 elseThe result.
- Clean HTML output
- Preserved code formatting
Which matters a lot on a technical blog.
Why SVG icons are embedded directly in HTML Copied!
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 Copied!
External images require additional HTTP requests.
Inline SVG becomes part of the HTML document.
HTML Download
│
▼
SVG already availableNo extra request.
2. Perfect scalability Copied!
SVG uses vector paths.
That means it scales without losing quality.
Small icon → large icon → same sharpnessRaster formats like PNG or JPG cannot do that.
3. CSS styling Copied!
Inline SVG can be styled with CSS.
Example.
svg {
stroke: currentColor;
}Icons automatically adapt to themes and colors.
Image optimization with Astro assets Copied!
Large images can easily dominate page weight.
Astro provides an excellent tool for this through astro:assets.
Two helpers appear often in the project.
getImagePicture
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 downloadedNo wasted bandwidth.
The Picture component for content images Copied!
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 imageThe browser picks the right one depending on screen size.
That keeps images crisp while avoiding oversized downloads.
CSS splitting strategy Copied!
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.cssComponents import their own styles when needed.
import "@styles/glass.css";This keeps styling modular.
How Astro bundles CSS and JavaScript Copied!
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 pageIf a component only appears on one page, its styles are not loaded anywhere else.
Global and local assets working together Copied!
The final architecture uses two layers.
Global assets Copied!
Loaded everywhere.
Examples.
- global CSS
- fonts
- layout scripts
- navigation styles
These are stable and reused across the site.
Local assets Copied!
Loaded only when needed.
Examples.
- component CSS
- feature scripts
- page specific styles
Astro merges them during the build.
Global CSS
│
▼
Component CSS
│
▼
Page bundleThe browser receives a single optimized bundle for the page being visited.
That avoids unused styles and unnecessary JavaScript.
Why these optimizations matter Copied!
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.
