Featured image of post Tại Sao Production Vẫn Chạy Code Cũ Thế?

Tại Sao Production Vẫn Chạy Code Cũ Thế?

Vừa deploy code mới nhưng web vẫn hiện cái nút cũ rích từ tuần trước? Hãy cùng ngồi xuống nói chuyện về trí nhớ 'qua dai' của trình duyệt và cách xử lý nó.

Đã bao giờ bạn mất cả 30 phút cuộc đời chỉ để F5 trình duyệt, xóa cache, bật tab ẩn danh (incognito), thậm chí đổi cả wifi chỉ vì cái nút bạn vừa đổi màu trên local nó không chịu hiện trên production chưa?

Ở máy mình (Localhost)? Mượt. Lên mạng (Production)? Vẫn là cái web từ tuần trước.

Nếu bạn đang deploy lên Firebase, Vercel, hay Netlify và từng hét vào màn hình “NHƯNG MÁY TAO CHẠY NGON MÀ!”, bài viết này là dành cho bạn.

Câu Chuyện Về Người Pha Chế “Hay Quên”

Hãy tưởng tượng một quán cà phê quen thuộc. Sáng nào bạn cũng ghé và gọi đúng một món: “Cho ly như cũ nha em!” (một ly bạc xỉu đá).

Bạn pha chế (Barista) đã quá quen mặt bạn. Vừa thấy bóng bạn từ xa, bạn ấy đã múc sẵn một ly để lên mặt quầy vì biết thừa bạn sẽ gọi món đó. Nhanh gọn, lẹ làng.

Nhưng hôm nay đẹp trời, bạn muốn đổi gió. Bạn muốn uống “Như cũ… nhưng ít sữa thôi”.

Bạn bước vào, hô to “Như cũ nha em!”, và bùm—bạn nhận được ngay ly bạc xỉu y chang hôm qua (nhiều sữa).

“Ủa không,” bạn nói, “Nay anh đổi món mà!” “Dạ xin lỗi anh,” bạn pha chế đáp, “Tại lệnh ghi là ‘Như cũ’, nên em đưa cái ly em làm sẵn cho lẹ.”

Đó chính là Caching.

Nhưng khoan, thực ra có tới hai tầng “người” đang ngăn cản bạn nhận ly nước mới:

  1. Trí não của bạn (Browser): Bạn nhớ ra mình còn ly cà phê uống dở hôm qua để trên bàn. Tiện tay cầm lên uống luôn cho lẹ khỏi đi mua.
  2. Quản lý cửa hàng (CDN): Kể cả khi bạn lết xác ra quán, ông Quản lý (Cloudflare/Firebase) đã đứng ngay cửa với một khay “Bạc xỉu” pha sẵn từ sáng sớm để phát cho khách. Ổng chặn bạn lại, đưa nước, rồi đẩy bạn ra về. Bạn còn chưa kịp gặp người pha chế (Server) gốc luôn cơ.
  • Bạn = Trình duyệt (Browser)
  • Quản lý = CDN (Cloudflare/Firebase)
  • Người pha chế = Máy chủ gốc (Origin Server)
  • “Ly như cũ” = File main.js hoặc style.css

Khi trang web yêu cầu file main.js, ông CDN sẽ lục kho và bảo: “À, tôi có 1000 bản copy của main.js từ hôm qua nè. Xài đỡ đi!”

Yêu cầu của bạn còn chưa chạm tới được máy chủ. CDN đã chặn đầu rồi. Nó không quan tâm nội dung file có gì thay đổi đâu, nó chỉ nhìn tên file thôi.

Giải Pháp: Đổi Tên Món Gọi

Làm sao để chắc chắn bạn nhận được ly nước mới? Đừng gọi “Ly như cũ”. Hãy gọi “Đơn hàng #90210”.

Ngày mai muốn uống món khác? Gọi “Đơn hàng #90211”.

Lúc này, bạn pha chế không thể đưa ly cũ cho bạn được, vì mã số trên ly cũ không khớp với mã bạn vừa đọc. Họ bắt buộc phải làm ly mới.

Trong lập trình web, cái này gọi là Asset Fingerprinting (hoặc Cache Busting).

Thay vì bảo trình duyệt tải main.js, ta bảo nó tải main.abc12345.js.

Khi ta sửa code, ta đổi luôn tên file: main.xyz98765.js. Trình duyệt thấy cái tên lạ hoắc chưa gặp bao giờ -> Bắt buộc phải tải mới.

Sửa Lỗi Này Trong Hugo

Nếu bạn dùng Hugo, bạn không cần đổi tên file bằng tay (may phước). Hugo có hàm resources.Fingerprint để làm việc đó tự động.

Trước đây code footer của tôi trông như này:

1
2
{{- $script := resources.Get "ts/main.ts" | js.Build $opts -}}
<script src="{{ $script.RelPermalink }}"></script>

Nó tạo ra file tên là main.js. Chán ngắt. Dễ bị cache. Nguy hiểm.

Tôi đổi nó thành:

1
2
{{- $script := resources.Get "ts/main.ts" | js.Build $opts | resources.Fingerprint "sha256" -}}
<script src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>

Giờ thì Hugo sẽ tạo ra file dạng: /ts/main.50550e6c64a7ed...2afc66aa.js

Mỗi khi tôi sửa dù chỉ một dấu chấm trong main.ts, chuỗi mã kia sẽ thay đổi. Mã mới = Tên file mới = Code mới cứng.

Bài Học Rút Ra

Browser caching là bạn thân của tốc độ, nhưng là kẻ thù của sự cập nhật (updates).

Đừng tin vào “Hard Refresh” (Ctrl+F5). Nó có thể sửa lỗi cho bạn, nhưng người dùng của bạn đâu có biết phím tắt đó. Họ sẽ chỉ thấy một trang web lỗi và vỡ layout.

Luôn luôn fingerprint (lấy dấu) các file tài nguyên (js/css) của bạn. Bắt người pha chế phải làm ly mới cho bạn mỗi ngày. ☕

Được tạo với sự lười biếng tình yêu 🦥

Subscribe to My Newsletter