Tăng điểm page speed cho blog này từ 91 lên 100
mở đầu
Sau nhiều năm lười biếng, giờ là lúc mình có động lực tạo một blog cá nhân. Động cơ xuất phát từ việc, càng già thì mình càng giỏi và giàu hơn có nhiều trăn trở hơn. Do đó mình tạo trang này để lưu lại (cũng như nhìn lại) suy nghĩ của bản thân qua năm tháng.
Mục đích đã có, giờ là lúc bắt tay vào việc nào. Vào wordpress.com đăng kí tài khoản, viết và xuất bản thôi 👌. Nếu vậy thì sẽ không có bài post này 🤣. Nhìn từ góc độ ROI (return of investment) thì Wordpress
là phương án phù hợp nhất. Tuy nhiên, đây là trang blog cá nhân nên mình sẽ tiếp cận theo hướng thiên technical một chút để còn múa máy 🕺 cũng như cá nhân hóa vài thành phần trong trang.
Để tiết kiệm thời gian thì mình đã fork
lại repo này astro-theme-cactus. Sau khi xóa bớt vài thành phần không cần thiết cũng như thêm bài blog đầu tiên, mình thử đo điểm page speed thì được 91 điểm. Điểm này thì khá ổn rồi, nhưng mình mang tiếng làm FE mà không được 100 điểm thì kém quá khá rảnh nên mình tìm cách để tối ưu nó lên 100 điểm 😌.
Sau đây là một vài giải pháp mình đã áp dụng để cải thiện điểm.
ảnh
- trong trang này, mình dùng đúng một ảnh (là cái avatar ở trên kìa) và nó cũng khá nhẹ nên không tối ưu cũng không sao. tuy nhiên, tiện tay thì mình làm luôn.
- mình dùng squoosh để tối ưu dung lượng ảnh cũng như convert ảnh từ
png
sangwebp
. ngoài ra, mình cũng giảm kích cỡ ảnh từ320x320
(ảnh gốc) xuống160x160
. - kết quả của bước này là ảnh giảm từ
2.5KB
xuống0.85KB
.
font chữ
- thay vì sử dụng nhiều
font-weight
khác nhau, mình chỉ dùng 2 variants làregular
vàsemibold
. - mình dùng font Space Grotesk. thay vì import font thông qua
Google Font CDN
như thông thường thì mình tải font về (và lưu vàopublic
) cũng như khai báostyle
trong thẻhead
luôn. tại sao lại làm như này thì xem tiếp nhé.
<!-- bỏ phần này -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600&display=swap"
rel="stylesheet"
/>
<!-- thêm phần này (copy từ content của link ngay trên) -->
<style>
/* vietnamese */
@font-face {
font-family: "Space Grotesk";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(/SG_Regular_Vn.woff2) format("woff2");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0,
U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin */
@font-face {
font-family: "Space Grotesk";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(/SG_Regular_Latin.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
U+FFFD;
}
/* vietnamese */
@font-face {
font-family: "Space Grotesk";
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(/SG_Semibold_Vn.woff2) format("woff2");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0,
U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin */
@font-face {
font-family: "Space Grotesk";
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(/SG_Semibold_Latin.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
U+FFFD;
}
</style>
khai báo trực tiếp
style
trong thẻhead
giúp giảm 1 round trip. khi đó, trình duyệt sẽ không phải tải nội dung từ link https://fonts.googleapis.com/css2?…1
rồi mới đi tải font. tiếp theo, việc này giúp mình kiểm soát được mình sẽ tải font-variant nào. như trong hình, bạn có thể so sánh nội dung link1
và nội dung thẻstyle
thì mình đã xóa được font-variantlatin-ext
là font-variant mình không dùng tới.mình tự host font trong
public
thay vì dùng thông quaGoogle Font CDN
vì có 2 lý do. thứ nhất, mình không biếtGoogle CDN
ở đâu, có nhanh nhưCloudflare
(là nơi host blog này) không. thứ hai, tự host font cho phép mình kiểm soát việc cache của font thay vì phụ thuộc vàoGoogle CDN
.mình thêm fallback font
Space Grotesk Fallback
vào thẻhead
. font này sẽ được hiển thị trong khi font thậtSpace Grotesk
đang được tải. điểm hay của nó là nó đã được tinh chỉnh các thông số để nó hiển thị gần giống font thật. do đó, khi font thật đã được tải xong và hiển thị thay thế fallback font, sựlayout shift
sẽ được giảm tối đa. để tính các thông số này thì bạn có thể dùng qua tool này của bácMalte Ubl
hoặc tự chỉnh tay thôi.
<style>
@font-face {
font-family: "Space Grotesk Fallback";
src: local("Arial");
ascent-override: 95.64%;
descent-override: 24.02%;
line-gap-override: 0%;
size-adjust: 105.45%;
}
/* khai bảo font Space Grotesk (đã show ở trên) */
</style>
- kết quả của bước này là giảm được 1 round trip, vài chục
KB
dung lượng font cũng như giảm sựlayout shift
.
các thư viện JavaScript
- trong trang này, mình dùng 2 thư viện
JavaScript
làpagefind
để tìm kiếm nội dung vàcusdis
để bình luận. để giảm thiểu dung lượng tải ban đầu của trang thì mình chỉ tải 2 thư viện này khi chúng được tương tác. cụ thể là chỉ tảipagefind
khi người dùng bấm vào biểu tượng tìm kiếm và chỉ tảicusdis
khi người dùng cuộn chuột tới cuối trang.
// chỉ load pagefind khi click vào 'openBtn'
const initSearch = async () => {
const { PagefindUI } = await import("@pagefind/default-ui");
return new PagefindUI({ element: "#cactus__search" });
};
const openModal = (event) => {
dialog.showModal();
initSearch();
};
openBtn.addEventListener("click", openModal);
// chỉ load cusdis khi nó visible
<CusdisWidget attrs={{ host: "https://cusdis.com", appId: "1", pageId: post.id }} client:visible />
- kết quả của bước này là giảm được
20KB
khi mới tải trang.
CSS
- như đã chia sẻ ở trên, trong trang này mình dùng thư viện
pagefind
. ngoài phần codeJavaScript
nêu ở phần trên, thư viện này còn có ~10KB
CSS
code đi kèm. chưa kể khoảng3KB
CSS
mình thêm vào để custom việc hiển thị của thư viện này. do thư viện này không cần dùng luôn ngay sau khi tải trang, thay vì import trực tiếp, mình sẽ injectCSS
khi người dùng nhấn nút tìm kiếm
styles/search.css
@import "@pagefind/default-ui/css/ui.css";
:root {
--pagefind-ui-font: inherit;
}
#cactus__search .pagefind-ui__search-clear {
width: calc(60px * var(--pagefind-ui-scale));
padding: 0;
background-color: transparent;
overflow: hidden;
}
Search.astro
// ...
const initSearch = async () => {
if (document.querySelector(".pagefind-ui__search-input")) return;
const searchStyles = await import("../styles/search.css?inline");
const styleTag = document.createElement("style");
styleTag.id = "search";
styleTag.innerHTML = searchStyles.default || "";
document.head.appendChild(styleTag);
};
// ...
- kết quả ở bước này là giảm được khoảng
10KB
khi mới tải trang .
ưu tiên preload
- trang này không có nhiều assets ngoài 1 cái ảnh, do đó mình preload load font để font được hiển thị sớm nhất có thể. khi đó, font sẽ được tải ngay khi
*.html
được tải xong.
<title>Some title</title>
<link rel="preload" href="/SG_Regular_Vn.woff2" as="font" type="font/woff2" />
<link rel="preload" href="/SG_Regular_Latin.woff2" as="font" type="font/woff2" />
<link rel="preload" href="/SG_Semibold_Vn.woff2" as="font" type="font/woff2" />
<link rel="preload" href="/SG_Semibold_Latin.woff2" as="font" type="font/woff2" />
...
<style></style>
- kết quả ở bước này là waterfall có sự cải thiện.
trước
sau
cache
- bước này thì đơn giản rồi. mình config file
_headers
đểCloudflare
cache các page trong 60s và các assets 6 tháng để người đọc đỡ phải tải lại trang nhiều lần. file hơi dài do mình copy / paste và lười chưa sắp xếp lại 🫠.
/
Cache-Control: max-age=60, must-revalidate
/minh-la-ai/
Cache-Control: max-age=60, must-revalidate
/p/*
Cache-Control: max-age=60, must-revalidate
/*.css
Cache-Control: max-age=604800, must-revalidate, immutable
/*.js
Cache-Control: max-age=604800, must-revalidate, immutable
/*.png
Cache-Control: max-age=604800, must-revalidate, immutable
/*.webp
Cache-Control: max-age=604800, must-revalidate, immutable
/*.woff2
Cache-Control: max-age=604800, must-revalidate, immutable
- cache này cũng là một sự đánh đổi. người đọc sẽ tải trang rất nhanh ở lần truy cập thứ 2 trở đi, tuy nhiên nội dung sẽ không được cập nhật mới nhất trong một khoảng thời gian do đã bị cache trong trình duyệt. đối với mình thì không phải là vấn đề.
tổng kết
- các kỹ thuật tối ưu điểm page speed thì có nhiều, trên đây chỉ là một vài kỹ thuật cơ bản phù hợp với trang này. nó đúng với trang này nhưng chưa chắc đúng với trang khác 🙈. mọi kỹ thuật hầu hết xoay quanh việc tải ít assets (cache, lazy load, giảm round trip, …) và tránh việc render blocking.
- việc tối ưu lên 100 điểm trong hầu hết trường hợp là không cần thiết, chỉ nên tối ưu khi bạn quá rảnh như mình.
p/s
- một điều khá buồn cười là bác
Malte Ubl
nhắc ở trên làCTO
củaVercel
nhưng blog của bác này lại host ởNetlify
. Blog khá nay, nếu rảnh bạn có thể đọc. - một vài site để đánh giá trang web: