Skip to content

SEO và prerender ​

SEO là kênh thu hút chính (PRD §12), nên trang không thể chỉ là SPA rỗng.

Chiến lược ​

Ứng dụng vẫn là SPA Vite, nhưng mỗi URL quan trọng được prerender thành HTML tĩnh lúc build. Cloudflare Pages phục vụ file tĩnh trước; URL nào không có file sẽ rơi về SPA shell qua public/_redirects.

vite build              → dist/           (bundle trình duyệt + index.html khung)
vite build --ssr        → dist-ssr/       (entry-server.js)
node scripts/prerender  → dist/**/index.html + sitemap.xml

Quy trình prerender ​

  1. Gọi API lấy danh sách trường, đề thi, kỳ thi, giáo viên (phân trang cho đến hết).
  2. Dựng danh sách route: 8 trang tĩnh + một trang cho mỗi bản ghi.
  3. Với mỗi route, prefetch đúng những query mà trang cần, rồi renderToString.
  4. Chèn HTML, thẻ <head> và state của react-query vào khung index.html.
  5. Ghi ra dist/<đường-dẫn>/index.html.
  6. Sinh sitemap.xml (bỏ /tim-kiem và /so-sanh vì phụ thuộc tham số).

Nếu API không phản hồi, script vẫn tạo trang (thẻ meta đúng, nội dung do client nạp) và in cảnh báo — bản build không bị hỏng.

Quản lý thẻ head ​

<Seo> hoạt động theo hai chế độ tuỳ ngữ cảnh:

  • Lúc prerender: ghi vào HeadContext để entry-server đọc lại sau khi render, rồi renderHead() dựng chuỗi HTML.
  • Trên trình duyệt: useEffect ghi thẳng vào document.head khi người dùng điều hướng nội bộ.

Mỗi trang khai báo title, description, canonical, tuỳ chọn noindex và jsonLd.

Dữ liệu có cấu trúc ​

TrangKiểu schema.org
Trang chủWebSite kèm SearchAction
Hồ sơ trườngSchool (có alternateName, address, foundingDate)
Chi tiết kỳ thiEvent (có startDate, organizer, eventAttendanceMode)

Hydrate không gọi lại API ​

State của react-query được dehydrate vào window.__RQ_STATE__. Khi trang mở, HydrationBoundary nạp lại và các query đã có dữ liệu tươi (staleTime 60 giây) nên không phát sinh request nào — số liệu hiển thị ngay lập tức, kể cả khi mạng chậm.

Giới hạn hiện tại ​

  • Biến PRERENDER_MAX (mặc định 400) chặn số trang chi tiết mỗi loại. Khi dữ liệu thật vượt mức này, cần nâng giá trị hoặc chuyển sang render theo yêu cầu.
  • Các trang danh sách chỉ prerender trang 1 không kèm bộ lọc; các tổ hợp bộ lọc do client dựng và không nằm trong sitemap.
  • /tim-kiem gắn noindex — kết quả tìm kiếm không nên vào chỉ mục.

Tài liệu nội bộ dự án Chuyên Chọn.