Web Performance Optimization — Tối Ưu Tốc Độ Website
Các kỹ thuật tối ưu web performance: Core Web Vitals, lazy loading, code splitting, caching và hơn thế nữa.
Tốc độ website ảnh hưởng trực tiếp đến user experience và SEO. 53% user rời trang nếu load lâu hơn 3 giây.
Core Web Vitals — Google Nói Gì?#
| Metric | Tốt | Cần cải thiện | Kém |
|---|---|---|---|
| LCP (Largest Contentful Paint) | ≤ 2.5s | ≤ 4s | > 4s |
| INP (Interaction to Next Paint) | ≤ 200ms | ≤ 500ms | > 500ms |
| CLS (Cumulative Layout Shift) | ≤ 0.1 | ≤ 0.25 | > 0.25 |
1. Images — Nặng Nhất Trang#
Lazy Loading#
<img src="image.jpg" loading="lazy" alt="..." />htmlChỉ tải ảnh khi user chuẩn bị scroll đến — tiết kiệm bandwidth, giảm initial load time.
WebP / AVIF#
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="...">
</picture>htmlWebP nhỏ hơn JPEG 25-35%, AVIF nhỏ hơn 50%.
Responsive Images#
<img
src="image-800.jpg"
srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w"
sizes="(max-width: 600px) 400px, 800px"
alt="..."
/>htmlTrình duyệt tự chọn ảnh phù hợp với viewport.
2. JavaScript — Kẻ Thù Của Performance#
Code Splitting#
// ❌ Tệ — import tất cả
import { Chart } from 'chart.js';
// ✅ Tốt — dynamic import
const Chart = await import('chart.js');
// React.lazy
const Dashboard = lazy(() => import('./Dashboard'));typescriptTree Shaking#
// ❌ Import cả thư viện
import { debounce } from 'lodash';
// ✅ Import đúng hàm
import debounce from 'lodash/debounce';typescriptAsync / Defer#
<!-- ❌ Block rendering -->
<script src="app.js"></script>
<!-- ✅ Tải song song, chạy sau khi parse HTML -->
<script defer src="app.js"></script>
<!-- ✅ Tải song song, chạy ngay khi tải xong -->
<script async src="analytics.js"></script>html3. CSS — Tối Ưu Render#
Critical CSS#
Inline CSS cần thiết cho above-the-fold, defer phần còn lại:
<head>
<style>
/* Critical CSS — inline trực tiếp */
header { ... }
.hero { ... }
</style>
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
</head>htmlLoại Bỏ CSS Không Dùng#
npx purgecss --css styles.css --content "src/**/*.html" --output dist/bash4. Font — Tránh FOIT (Flash of Invisible Text)#
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- font-display: swap — hiển thị text ngay với fallback font -->
<style>
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap;
}
</style>htmlKhông dùng quá 2 font families và subset font để giảm kích thước:
# glyphhanger — subset font
glyphhanger https://example.com --subset=*.ttf --formats=woff2bash5. Caching — Đừng Để Browser Phải Tải Lại#
HTTP Cache Headers#
// Static assets — cache lâu
app.use('/assets', express.static('dist', {
maxAge: '1y',
immutable: true,
}));
// HTML — không cache hoặc cache ngắn
app.get('/', (req, res) => {
res.set('Cache-Control', 'no-cache');
res.sendFile('index.html');
});typescriptService Worker#
// sw.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/',
'/styles.css',
'/app.js',
]);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});typescript6. Network — Giảm Số Request#
HTTP/2 Multiplexing#
HTTP/2 cho phép gửi nhiều file song song qua một connection. Không cần concatenate JS/CSS thành một file như thời HTTP/1.1.
Preload / Prefetch / Preconnect#
<!-- Preload — tải sớm resource quan trọng -->
<link rel="preload" href="/fonts/inter.woff2" as="font" crossorigin>
<!-- Prefetch — tải trước trang user có thể visit -->
<link rel="prefetch" href="/blog/microservices">
<!-- Preconnect — kết nối trước đến origin -->
<link rel="preconnect" href="https://api.example.com">html7. Bundle Size — Theo Dõi#
# Phân tích bundle
npx vite-bundle-visualizer
# hoặc
npx source-map-explorer dist/assets/*.jsbashĐặt threshold trong CI:
{
"scripts": {
"size": "bundlesize",
"bundlesize": [
{ "path": "dist/assets/*.js", "maxSize": "100 kB" }
]
}
}json8. Lighthouse Score — Tự Động Kiểm Tra#
# Lighthouse CI
npx lhci autorun
# Hoặc web vitals trong code
import { onLCP, onINP, onCLS } from 'web-vitals';
onLCP(console.log);
onINP(console.log);
onCLS(console.log);bashChecklist Tối Ưu#
- Images: WebP/AVIF, lazy loading, responsive
- JS: code splitting, tree shaking, defer
- CSS: critical CSS inline, purge unused
- Font: display swap, subset, preconnect
- Caching: Cache-Control, service worker
- Preload critical resources
- HTTP/2 enabled
- Lighthouse score > 90
- Core Web Vitals all “Good”
Kết Luận#
Performance là tính năng. Không phải thứ “làm sau” — nó ảnh hưởng đến revenue, user retention, SEO. Bắt đầu từ images (thường là thủ phạm nặng nhất), sau đó đến JS và font. Đo lường trước và sau để thấy sự khác biệt.