Why Performance Matters
Slow pages keep visitors waiting and can interrupt their visit before they send an enquiry or make a purchase. Before changing anything, find out what is slowing the site down.
Here are practical ways to improve images, code delivery, caching, and server performance.
1. Optimize Images
Large image files can account for a substantial part of a page's size. Start by checking their dimensions and file sizes.
Use modern formats
<!-- Use WebP with fallback -->
<picture>
<source srcset="image.webp" type="image/webp" />
<img src="image.jpg" alt="Description" />
</picture>
Lazy load images further down the page
<!-- Built-in browser lazy loading -->
<img src="image.jpg" loading="lazy" alt="Description" />
Key practices:
- Compress images (TinyPNG, ImageOptim)
- Use appropriate dimensions (don't load 4000px images for 400px displays)
- Implement responsive images with
srcset
2. Reduce the JavaScript Payload
Reduce JavaScript payload:
// Before: importing the entire library
import _ from 'lodash'
const result = _.debounce(fn, 300)
// After: Import only what you need
import debounce from 'lodash/debounce'
const result = debounce(fn, 300)
Code splitting
Split your code into smaller chunks:
// Dynamic imports
const HeavyComponent = () => import('./HeavyComponent.vue')
// Load only when needed
if (userWantsFeature) {
const module = await import('./feature.js')
module.init()
}
3. Implement Caching Strategies
Browser caching
# Nginx configuration
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Service Workers
Cache assets for offline access:
// service-worker.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll(['/', '/styles/main.css', '/scripts/main.js'])
})
)
})
4. Optimize CSS Delivery
Critical CSS
Inline critical CSS for above-the-fold content:
<head>
<style>
/* Critical CSS inline */
.hero {
background: #000;
height: 100vh;
}
</style>
<link
rel="preload"
href="/styles/main.css"
as="style"
onload="this.rel='stylesheet'"
/>
</head>
Remove unused CSS
Remove styles the page does not use. This example shows content-based CSS removal in an older Tailwind configuration; the exact setup depends on your version:
// Tailwind CSS config
module.exports = {
purge: ['./src/**/*.{js,jsx,ts,tsx,vue}'],
// ...
}
5. Use Content Delivery Networks (CDN)
Content delivery networks serve files from locations near your users. Examples include:
- Cloudflare
- AWS CloudFront
- Vercel and Netlify
Possible benefits:
- Reduced latency
- Better global performance
- Less load on the origin server
- Protection and optimisation features, depending on the service
6. Optimize Fonts
Web fonts can significantly impact load time:
Preload a font in HTML:
<link
rel="preload"
href="/fonts/custom.woff2"
as="font"
type="font/woff2"
crossorigin
/>
Control how text appears while the font loads in CSS:
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap; /* Show fallback immediately */
}
Best practices:
- Use system fonts when possible
- Limit font weights and variants
- Use WOFF2 format
- Self-host fonts to avoid external requests
7. Database Query Optimization
Slow database queries can increase server response time:
-- A query that may require scanning the whole table
SELECT * FROM users WHERE email LIKE '%@example.com';
-- An indexed query for an exact email address match
CREATE INDEX idx_users_email ON users(email);
SELECT id, name, email FROM users WHERE email = '[email protected]';
Tips:
- Add indexes on frequently queried columns
- Select the columns you need rather than using
* - Implement database connection pooling
- Cache frequent queries (Redis, Memcached)
8. Enable Compression
Compress text-based assets:
# Enable Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
gzip_min_length 1000;
Brotli is another compression option. The appropriate configuration depends on your server and the files being served.
9. Monitor and Measure
Measure before and after making changes:
Tools:
- Google PageSpeed Insights: Overall performance score
- Lighthouse: Detailed audits
- WebPageTest: Real-world testing
- Chrome DevTools: Network and performance profiling
Key user experience metrics:
- LCP (Largest Contentful Paint): loading performance; a good result is 2.5 seconds or less
- INP (Interaction to Next Paint): responsiveness to user input; a good result is 200 ms or less
- CLS (Cumulative Layout Shift): visual stability; a good result is 0.1 or less
Google's Core Web Vitals guide assesses these thresholds at the 75th percentile of visits. At least 75% of visits should fall within the good range for each metric.
10. Server-Side Optimization
Use HTTP/2 or HTTP/3
listen 443 ssl http2;
HTTP/2 supports multiple requests over one connection and header compression.
Implement server-side caching
// Node.js example with Redis
const redis = require('redis')
const client = redis.createClient()
app.get('/api/data', async (req, res) => {
const cached = await client.get('data')
if (cached) {
return res.json(JSON.parse(cached))
}
const data = await fetchFromDatabase()
await client.setex('data', 3600, JSON.stringify(data))
res.json(data)
})
How to Assess the Result
Compare loading times and user experience metrics on the same pages under similar conditions. Look at phone and desktop users separately. Where possible, compare test results with data from real visitors.
To assess business impact, also track enquiries or purchases. Remember that your offer, traffic sources, and seasonality affect those figures too.
Conclusion
Improving website speed is ongoing work. Measure first, address the biggest bottlenecks, and check the effect of each change. Images, caching, and the amount of code sent to the browser are often useful starting points.
