Skip to content

Chế độ render

Mặc định của framework: Nitro chạy trên server, giao diện render ở trình duyệt. Nghe mâu thuẫn với "Nuxt SSR" nên trang này nói rõ vì sao và khi nào phá lệ.

SSR không phải BFF

Hai thứ hay bị gộp làm một:

Chạy ở đâuFramework dùng để làm gì
Nitro / BFFServerProxy /api/**, giữ cookie phiên httpOnly, gọi IAM. Luôn bật
SSR (render component)ServerSinh HTML sẵn cho trang. Mặc định tắt

Cấu hình trong layer:

ts
ssr: true,                              // giữ Nitro + BFF
routeRules: { '/**': { ssr: false } },  // nhưng trang thì render ở client

Đừng đặt ssr: false ở cấp nuxt.config. Làm vậy là bỏ hẳn khả năng render phía server: không route nào bật lại được nữa (routeRules: { ssr: true } mất tác dụng), và nếu triển khai dạng tĩnh (nuxi generate + hosting tĩnh) thì Nitro không chạy — /api/**, /auth/** và chỗ trú của token biến mất cùng. Giữ ssr: true, điều chỉnh bằng routeRules.

Vì sao mặc định CSR

Ant Design Vue 4 dùng cssinjs, render phía server còn nhiều điểm gãy:

  • FOUC: style chèn sau khi HTML đã hiện, trang nháy một nhịp không có định dạng.
  • Hydration mismatch: component dùng Teleport (Modal, Drawer, Dropdown, Tooltip) và các nhánh responsive cho kết quả khác nhau giữa server và client.
  • message / notification gọi theo kiểu lệnh, khởi tạo ngoài cây component nên mất theme khi chạy trên server.

Đổi lại, app nội bộ sau đăng nhập không cần SEO và người dùng vào bằng link trực tiếp rất ít. CSR là lựa chọn đơn giản và ổn định nhất cho phần lớn màn hình.

Điều này ảnh hưởng gì tới cách viết trang

  • useAsyncData / useFetch vẫn dùng bình thường, chỉ là chúng chạy ở client.
  • Đừng trông chờ HTML có sẵn nội dung: luôn xử lý trạng thái đang tải (CTable :loading, skeleton, CEmpty).
  • import.meta.server gần như luôn false trong code trang; logic chỉ chạy được trên server thì đưa vào server/ (route Nitro).
  • window, localStorage dùng được trong onMounted mà không cần bọc <ClientOnly> — nhưng vẫn nên tránh dùng ở top-level <script setup> để trang còn bật SSR được sau này.

Bật SSR cho một route

Trang công khai cần SEO hoặc first-paint nhanh (landing, trang tra cứu công khai, link chia sẻ):

ts
// nuxt.config.ts của dự án
export default defineNuxtConfig({
  extends: ['@tasco/nuxt-layer-base'],
  routeRules: {
    '/landing': { ssr: true },
    '/tra-cuu/**': { ssr: true },
  },
})

routeRules merge sâu nên chỉ cần khai route muốn đổi; phần '/**': { ssr: false } của layer vẫn giữ cho những route còn lại.

Route bật SSR phải tự né các điểm đau của antdv:

vue
<template>
  <!-- Nội dung tĩnh: render được trên server, tốt cho SEO -->
  <CPageHeader title="Tra cứu đơn hàng" />

  <!-- Phần dùng Teleport/responsive: để client render -->
  <ClientOnly>
    <CTable :columns="columns" :data-source="dataSource" />
  </ClientOnly>
</template>

Và dùng App.useApp() của antdv thay cho message/notification gọi trực tiếp, để chúng lấy được theme từ context.

Kiểm tra thật trước khi bật

Bật SSR cho một route là quyết định của dự án, không có sẵn bảo chứng từ core. Kiểm tra: tắt JavaScript xem HTML có đủ nội dung không, mở console tìm cảnh báo hydration, và xem trang có nháy style lúc tải.

Các tuỳ chọn routeRules khác

RuleTác dụngKhi nào dùng
{ ssr: false }Trang render ở clientMặc định của layer
{ ssr: true }Render HTML trên serverTrang công khai cần SEO
{ prerender: true }Sinh HTML tĩnh lúc buildTrang nội dung không đổi theo người dùng
{ headers: { 'cache-control': '...' } }Đặt header cho responseTài nguyên tĩnh của dự án

Không đặt redirect hay proxy trong routeRules cho /api/**: phần đó đã do BFF của layer xử lý, thêm rule sẽ vượt mặt và làm mất token. Xem BFF.

Liên quan