Skip to content

Astro Performance Optimization

Astro đã nhanh theo mặc định, nhưng bạn có thể làm cho nó nhanh hơn nữa. Bài viết này tổng hợp các kỹ thuật optimization từ cơ bản đến nâng cao.

<!-- ❌ Không cần JS -->
<StaticContent />
<!-- ✅ Hydrate ngay -->
<InteractiveCounter client:load />
<!-- ✅ Hydrate khi browser idle -->
<Comments client:idle />
<!-- ✅ Hydrate khi visible -->
<Testimonials client:visible />
<!-- ✅ Hydrate ở màn hình nhỏ -->
<MobileMenu client:media="(max-width: 768px)" />
<!-- ✅ Chỉ client-side, không SSR -->
<Chart client:only="react" />
---
import { Image } from 'astro:assets';
import myImage from '../assets/image.png';
---
<!-- ✅ Tự động optimize -->
<Image
src={myImage}
alt="Description"
width={800}
height={400}
format="webp"
/>
<!-- ✅ Responsive images -->
<Image
src={myImage}
alt="Description"
widths={[400, 800, 1200]}
sizes="(max-width: 800px) 100vw, 800px"
/>
<!-- Tự động lazy load -->
<Image src={myImage} alt="Description" loading="lazy" />
<!-- Eager load cho LCP image -->
<Image src={heroImage} alt="Hero" loading="eager" />
<!-- Dùng với external URLs -->
<img
src="https://example.com/image.jpg"
alt="Description"
loading="lazy"
decoding="async"
/>
/* ✅ Hiển thị text ngay, swap font sau */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter.woff2') format('woff2');
font-display: swap;
}
<!-- Trong <head> -->
<link
rel="preload"
href="/fonts/Inter.woff2"
as="font"
type="font/woff2"
crossorigin
/>
Terminal window
# Chỉ include characters cần thiết
npx glyphhanger https://yoursite.com \
--subset=/fonts/Inter.ttf \
--formats=woff2
astro.config.mjs
import purgecss from 'astro-purgecss';
export default defineConfig({
integrations: [
purgecss({
safelist: ['dark', 'light'], // Classes không được purge
}),
],
});
---
// Inline critical CSS
---
<style is:inline>
/* CSS cho Above-the-fold content */
.hero { /* ... */ }
.navbar { /* ... */ }
</style>
<!-- Non-critical CSS async -->
<link rel="preload" href="/styles/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
---
// Chỉ load CSS cho page này
import '../styles/blog.css';
---
<!-- ❌ Block rendering -->
<script src="/analytics.js"></script>
<!-- ✅ Load async -->
<script src="/analytics.js" async></script>
<!-- ✅ Execute sau khi parse xong -->
<script src="/analytics.js" defer></script>
<script>
// Chỉ load khi cần
document.querySelector('#load-map').addEventListener('click', async () => {
const { initMap } = await import('./map.js');
initMap();
});
</script>
astro.config.mjs
export default defineConfig({
build: {
format: 'file', // Hash filenames for caching
},
vite: {
build: {
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // Xóa console.log
},
},
},
},
});
astro.config.mjs
export default defineConfig({
vite: {
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor': ['react', 'react-dom'],
'ui': ['./src/components/ui/index.js'],
},
},
},
},
},
});
netlify.toml
[[headers]]
for = "/_astro/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/images/*"
[headers.values]
Cache-Control = "public, max-age=2592000"
public/sw.js
const CACHE_NAME = 'site-v1';
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll([
'/',
'/styles/main.css',
'/scripts/app.js',
]);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});
<!-- Prefetch on hover -->
<a href="/about" data-astro-prefetch>About</a>
<!-- Prefetch ngay -->
<a href="/blog" data-astro-prefetch="load">Blog</a>
<!-- Prefetch khi visible -->
<a href="/contact" data-astro-prefetch="viewport">Contact</a>
astro.config.mjs
import prefetch from '@astrojs/prefetch';
export default defineConfig({
integrations: [
prefetch({
selector: "a[href^='/']",
throttle: 3,
}),
],
});
.github/workflows/lighthouse.yml
name: Lighthouse CI
on: [push]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npm run build
- uses: treosh/lighthouse-ci-action@v9
with:
configPath: './lighthouserc.json'
lighthouserc.json
{
"ci": {
"assert": {
"assertions": {
"categories:performance": ["error", { "minScore": 0.9 }],
"categories:accessibility": ["error", { "minScore": 0.9 }],
"categories:best-practices": ["error", { "minScore": 0.9 }],
"categories:seo": ["error", { "minScore": 0.9 }]
}
}
}
}
<script>
// Theo dõi Core Web Vitals
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('LCP:', entry.startTime);
}
}).observe({ entryTypes: ['largest-contentful-paint'] });
</script>
  • Lighthouse score 90+ (all categories)
  • Core Web Vitals đạt chuẩn
  • Images optimized (WebP/AVIF)
  • Fonts subset và swap
  • CSS minified và purged
  • JS split và lazy loaded
  • Caching headers configured
  • Gzip/Brotli enabled
ToolMục đích
LighthouseAudit performance
WebPageTestTest từ nhiều location
GTmetrixPerformance monitoring
BundlephobiaAnalyze package size
PurgeCSSRemove unused CSS