Posted on 28th May 2026 at 07:00 by Millie
Why I moved them from public to src/assets/images in the first place
Astro recommends having images in /src/assets/images because it can then optimise and hash them when building the site.
Optimise means compress and convert to webp. I can do that with ImageMack.
Hash means adding cache busting to the image file name. I don’t need this because my images never change.
You can’t load images from /src/assets/images with HTML in an MD file, only from /public. (Possibly from /public/assets/images, but I’ll investigate that another time)
Solution
- Move all images to /public
- Change format and extension to webp with ImageMagick. (I’m going to have to change all the image file references in my pages and posts anyway.)
Gemini’s optimisation script
import fs from 'fs';
import path from 'path';
import sharp from 'sharp';
// Path where Astro outputs your static build files
const distDir = path.join(process.cwd(), 'dist');
async function processDirectory(directory) {
const files = fs.readdirSync(directory);
for (const file of files) {
const fullPath = path.join(directory, file);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
await processDirectory(fullPath);
} else {
const ext = path.extname(file).toLowerCase();
// Only process common image formats
if (['.jpg', '.jpeg', '.png'].includes(ext)) {
const buffer = fs.readFileSync(fullPath);
// Convert the image data to optimized webp format internally,
// but write it back to the original filename/extension
await sharp(buffer)
.webp({ quality: 80 })
.toFile(fullPath);
console.log(`Optimized: ${fullPath}`);
}
}
}
}
console.log('Starting image post-optimization...');
processDirectory(distDir).then(() => console.log('Optimization complete!'));
Update package.json
"scripts": {
"dev": "astro dev",
"build": "astro build && node optimize.js",
"preview": "astro preview",
"astro": "astro"
}
Run optimisation
% npm run optimize.js