Skip to content

Server-Side Rendering (SSR)

Tổng quan

SSR là gì?

Vue.js là một framework để xây dựng ứng dụng phía client. Theo mặc định, các thành phần Vue tạo và điều khiển DOM trong trình duyệt như là kết quả. Tuy nhiên, cũng có thể hiển thị các thành phần giống nhau thành chuỗi HTML trên máy chủ, gửi chúng trực tiếp đến trình duyệt, và cuối cùng "hydrate" (thức tỉnh) đánh dấu tĩnh thành một ứng dụng tương tác đầy đủ trên máy khách.

Một ứng dụng Vue.js được hiển thị trên máy chủ cũng có thể được coi là "isomorphic" hoặc "universal", trong ý nghĩa rằng phần lớn mã nguồn của ứng dụng chạy trên cả máy chủ máy khách.

Tại sao lại sử dụng SSR?

So với ứng dụng Single-Page Application (SPA) phía client, ưu điểm chủ yếu của SSR nằm ở:

  • Thời gian hiển thị nội dung nhanh hơn: điều này trở nên rõ ràng hơn trên internet chậm hoặc trên thiết bị chậm. Đánh dấu của máy chủ không cần phải đợi cho đến khi tất cả JavaScript đã được tải xuống và thực thi mới hiển thị, vì vậy người dùng sẽ thấy một trang được hiển thị đầy đủ sớm hơn. Ngoài ra, việc truy xuất dữ liệu được thực hiện phía máy chủ trong lần truy cập ban đầu, có thể có kết nối tới cơ sở dữ liệu nhanh hơn so với máy khách. Điều này thường dẫn đến cải thiện về Core Web Vitals metrics, trải nghiệm người dùng tốt hơn và có thể quan trọng đối với các ứng dụng nơi thời gian hiển thị nội dung liên quan trực tiếp đến tỷ lệ chuyển đổi.

  • Mô hình tâm lý thống nhất: bạn có thể sử dụng cùng ngôn ngữ và mô hình tâm lý khai báo, hướng thành phần để phát triển toàn bộ ứng dụng của bạn, thay vì nhảy liên tục giữa một hệ thống mẫu backend và một framework frontend.

  • SEO tốt hơn: crawler của công cụ tìm kiếm sẽ nhìn thấy trang đã được hiển thị đầy đủ.

    TIP

    Hiện tại, Google và Bing có thể chỉ mục các ứng dụng JavaScript đồng bộ một cách bình thường. Từ "đồng bộ" là từ khóa ở đây. Nếu ứng dụng của bạn bắt đầu với một spinner, sau đó truy xuất nội dung qua Ajax, crawler sẽ không đợi bạn kết thúc. Điều này có nghĩa là nếu bạn có nội dung được truy xuất bất đồng bộ trên các trang nơi SEO quan trọng, thì có thể cần phải sử dụng SSR.

Tuy nhiên, cũng có những đối thoại cần xem xét khi sử dụng SSR:

  • Hạn chế trong quá trình phát triển. Mã nguồn chỉ dành cho trình duyệt chỉ có thể được sử dụng bên trong một số lifecycle hook cụ thể; một số thư viện bên ngoại có thể cần xử lý đặc biệt để có thể chạy trong ứng dụng có tính chất server-rendered.

  • Yêu cầu cấu hình xây dựng và triển khai phức tạp hơn. Khác với một SPA tĩnh hoàn toàn có thể triển khai trên bất kỳ máy chủ tệp tĩnh nào, một ứng dụng server-rendered yêu cầu môi trường nơi một máy chủ Node.js có thể chạy.

  • Tải động phía máy chủ nhiều hơn. Việc hiển thị một ứng dụng đầy đủ trong Node.js sẽ tốn nhiều CPU hơn so với việc chỉ phục vụ các tệp tĩnh, nên nếu bạn mong đợi lưu lượng lớn, hãy chuẩn bị cho tải động máy chủ tương ứng và sử dụng chiến lược caching một cách khôn ngoan.

Trước khi sử dụng SSR cho ứng dụng của bạn, câu hỏi đầu tiên bạn nên đặt ra là liệu bạn thực sự cần nó hay không. Điều này chủ yếu phụ thuộc vào việc thời gian hiển thị nội dung quan trọng như thế nào đối với ứng dụng của bạn. Ví

dụ, nếu bạn đang xây dựng một bảng điều khiển nội bộ nơi việc thêm một vài trăm mili giây trong lần tải ban đầu không quan trọng nhiều, thì việc sử dụng SSR có thể là quá mức. Tuy nhiên, trong các trường hợp mà thời gian hiển thị nội dung là quan trọng tuyệt đối, SSR có thể giúp bạn đạt được hiệu suất tải ban đầu tốt nhất có thể.

SSR vs. SSG

Tạo Trang Tĩnh (SSG), còn được gọi là pre-rendering, là một kỹ thuật phổ biến khác để xây dựng trang web nhanh chóng. Nếu dữ liệu cần thiết để hiển thị trang bằng cách sử dụng SSR là giống nhau đối với mọi người dùng, thì thay vì hiển thị trang mỗi khi có một yêu cầu, chúng ta có thể hiển thị nó chỉ một lần, trước thời gian, trong quá trình xây dựng. Trang được tạo trước sẽ được tạo và phục vụ dưới dạng tệp HTML tĩnh.

SSG giữ lại những đặc điểm về hiệu suất của ứng dụng SSR: nó mang lại hiệu suất tốt về thời gian hiển thị nội dung. Đồng thời, nó còn rẻ hơn và dễ triển khai hơn so với ứng dụng SSR vì đầu ra là HTML và tài nguyên tĩnh. Từ khóa ở đây là tĩnh: SSG chỉ có thể được áp dụng cho các trang tiêu thụ dữ liệu tĩnh, tức là dữ liệu biết tại thời điểm xây dựng và không thay đổi giữa các lần triển khai. Mỗi khi dữ liệu thay đổi, cần có một triển khai mới.

Nếu bạn chỉ đang xem xét SSR để cải thiện SEO của một số trang tiếp thị (ví dụ: /, /about, /contact, vv), thì có lẽ bạn muốn SSG thay vì SSR. SSG cũng rất tốt cho các trang web dựa trên nội dung như trang tài liệu hoặc blog. Trên thực tế, trang web bạn đang đọc ngay bây giờ được tạo tĩnh bằng cách sử dụng VitePress, một trình tạo trang tĩnh được động bằng Vue.

Hướng dẫn cơ bản

Hiển thị ứng dụng

Hãy xem xét ví dụ cơ bản nhất về Vue SSR trong hành động.

  1. Tạo một thư mục mới và cd vào nó.
  2. Chạy npm init -y.
  3. Thêm "type": "module" vào package.json để Node.js chạy ở chế độ ES modules.
  4. Chạy npm install vue.
  5. Tạo một tệp example.js:
js
// chạy trên Node.js trên máy chủ.
import { createSSRApp } from 'vue'
// API server-rendering của Vue được tiếp cận dưới `vue/server-renderer`.
import { renderToString } from 'vue/server-renderer'

const app = createSSRApp({
  data: () => ({ count: 1 }),
  template: `<button @click="count++">{{ count }}</button>`
})

renderToString(app).then((html) => {
  console.log(html)
})

Sau đó chạy:

sh
> node example.js

Nó nên in ra dòng sau trên dòng lệnh:

<button>1</button>

renderToString() nhận một thể hiện ứng dụng Vue và trả về một Promise giải quyết thành HTML được hiển thị của ứng dụng. Cũng có thể thực hiện hiển thị dòng sử dụng Node.js Stream API hoặc Web Streams API. Xem SSR API Reference để biết chi tiết đầy đủ.

Chúng ta có thể sau đó chuyển mã nguồn Vue SSR vào một người xử lý yêu cầu máy chủ, wrap phần đánh dấu ứng dụng với HTML trang đầy đủ. Chúng ta sẽ sử dụng express cho các bước tiếp theo:

  • Chạy npm install express.
  • Tạo tệp server.js sau:
js
import express from 'express'
import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'

const server = express()

server.get('/', (req, res) => {
  const app = createSSRApp({
    data: () => ({ count: 1 }),
    template: `<button @click="count++">{{ count }}</button>`
  })

  renderToString(app).then((html) => {
    res.send(`
    <!DOCTYPE html>
    <html>
      <head>
        <title>Vue SSR Example</title>
      </head>
      <body>
        <div id="app">${html}</div>
      </body>
    </html>
    `)
  })
})

server.listen(3000, () => {
  console.log('ready')
})

Cuối cùng, chạy node server.js và truy cập http://localhost:3000. Bạn nên thấy trang hoạt động với nút.

Thử nghiệm trên StackBlitz

Hydration ở phía Client

Nếu bạn nhấp vào nút, bạn sẽ nhận thấy số không thay đổi. HTML hoàn toàn tĩnh trên máy khách vì chúng ta không tải Vue trong trình duyệt.

Để làm cho ứng dụng phía client tương tác, Vue cần thực hiện bước hydration. Trong quá trình hydration, nó tạo ra cùng một ứng dụng Vue đã chạy trên máy chủ, so khớp từng thành phần với các nút DOM nó nên kiểm soát và gắn bộ lắng nghe sự kiện DOM.

Để gắn một ứng dụng trong chế độ hydration, chúng ta cần sử dụng createSSRApp() thay vì createApp():

js
// chạy trên trình duyệt.
import { createSSRApp } from 'vue'

const app = createSSRApp({
  // ...cùng ứng dụng như trên máy chủ
})

// gắn một ứng dụng SSR trên máy khách giả định
// rằng HTML đã được pre-rendered và sẽ thực hiện
// hydration thay vì gắn nút DOM mới.
app.mount('#app')

Cấu trúc mã nguồn

Lưu ý cách chúng ta cần tái sử dụng cùng một triển khai ứng dụng như trên máy chủ. Đây là nơi chúng ta cần bắt đầu nghĩ về cấu trúc mã nguồn trong một ứng dụng SSR - làm thế nào chúng ta có thể chia sẻ cùng một mã nguồn ứng dụng giữa máy chủ và máy khách?

Ở đây, chúng tôi sẽ thể hiện cài đặt cơ bản nhất. Trước hết, hãy chia logic tạo ứng dụng thành một tệp riêng, app.js:

js
// app.js (chia sẻ giữa máy chủ và máy khách)
import { createSSRApp } from 'vue'

export function createApp() {
  return createSSRApp({
    data: () => ({ count: 1 }),
    template: `<button @click="count++">{{ count }}</button>`
  })
}

Tệp này và các phụ thuộc của nó được chia sẻ giữa máy chủ và máy khách - chúng ta gọi chúng là mã chung. Có một số điều bạn cần chú ý khi viết mã chung, như chúng tôi sẽ thảo luận bên dưới.

Mục nhập máy khách của chúng tôi nhập mã chung, tạo ứng dụng và thực hiện việc gắn:

js
// client.js
import { createApp } from './app.js'

createApp().mount('#app')

Và máy chủ sử dụng cùng logic tạo ứng dụng trong xử lý yêu cầu:

js
// server.js (code không liên quan đã được loại bỏ)
import { createApp } from './app.js'

server.get('/', (req, res) => {
  const app = createApp()
  renderToString(app).then(html => {
    // ...
  })
})

Ngoài ra, để tải các tệp máy khách trong trình duyệt, chúng ta cũng cần:

  1. Cung cấp các tệp máy khách bằng cách thêm server.use(express.static('.')) trong server.js.
  2. Tải mã nguồn nhập máy khách bằng cách thêm <script type="module" src="/client.js"></script> vào HTML shell.
  3. Hỗ trợ việc sử dụng như import * from 'vue' trong trình duyệt bằng cách thêm một Import Map vào HTML shell.

Thử nghiệm ví dụ hoàn chỉnh trên StackBlitz. Nút bây giờ có thể tương tác!

Các Giải Pháp Cao Cấp

Chuyển từ ví dụ sang một ứng dụng SSR sẵn sàng cho sản xuất liên quan đến nhiều hơn. Chúng ta sẽ cần:

  • Hỗ trợ Vue SFCs và các yêu cầu xây dựng khác. Trên thực tế, chúng ta sẽ cần phối hợp hai xây dựng cho cùng một ứng dụng: một cho máy khách và một cho máy chủ.

    TIP

    Các thành phần Vue được biên dịch khác nhau khi sử dụng cho SSR - các mẫu được biên dịch thành chuỗi nối thay vì các hàm render Virtual DOM để tăng hiệu suất hiển thị hiệu suất.

  • Trong người xử lý yêu cầu máy chủ, hiển thị HTML với các liên kết tài sản phía máy khách chính xác và gợi ý tài nguyên tối ưu. Chúng ta cũng có thể cần chuyển đổi giữa chế độ SSR và SSG, hoặc thậm chí kết hợp cả hai trong cùng một ứng dụng.

  • Quản lý định tuyến, lấy dữ liệu và lưu trữ quản lý trạng thái một cách chung chung.

Một cài đặt hoàn chỉnh sẽ khá phức tạp và phụ thuộc vào chuỗi công cụ xây dựng bạn đã chọn để làm việc. Do đó, chúng tôi khuyến khích cao nhất là sử dụng một giải pháp có cấp độ cao, chủ quan hóa sự phức tạp cho bạn. Dưới đây, chúng tôi sẽ giới thiệu một số giải pháp SSR được khuyến nghị trong hệ sinh thái Vue.

Nuxt

Nuxt là một khung cao cấp được xây dựng trên cơ sở của hệ sinh thái Vue, cung cấp một trải nghiệm phát triển được tối ưu hóa cho việc viết ứng dụng Vue đa nền tảng. Hơn nữa, bạn cũng có thể sử dụng nó như một công cụ tạo trang tĩnh! Chúng tôi rất khuyến nghị thử nghiệm nó.

Quasar

Quasar là một giải pháp đầy đủ dựa trên Vue, cho phép bạn chọn mục tiêu SPA, SSR, PWA, ứng dụng di động, ứng dụng máy tính, và tiện ích trình duyệt tất cả đều sử dụng một mã nguồn. Nó không chỉ xử lý thiết lập xây dựng, mà còn cung cấp một bộ sưu tập đầy đủ các thành phần UI tuân thủ Thiết kế Vật liệu.

Vite SSR

Vite cung cấp hỗ trợ tích hợp cho việc k rendering phía máy chủ Vue, nhưng có chủ ý là ở mức thấp. Nếu bạn muốn tiếp tục trực tiếp với Vite, hãy kiểm tra vite-plugin-ssr, một plugin cộng đồng giản đơn nhiều chi tiết khó khăn cho bạn.

Bạn cũng có thể tìm thấy một dự án ví dụ Vue + Vite SSR sử dụng thiết lập thủ công ở đây, có thể phục vụ làm cơ sở để xây dựng lên. Lưu ý rằng điều này chỉ được khuyến nghị nếu bạn đã có kinh nghiệm với SSR / công cụ xây dựng và thực sự muốn kiểm soát hoàn toàn kiến trúc ở cấp độ cao.

Viết Mã Hỗ Trợ SSR

Bất kể bạn sử dụng thiết lập xây dựng hoặc lựa chọn framework cấp độ cao, có một số nguyên tắc áp dụng cho tất cả các ứng dụng Vue SSR.

Tính Linh Hoạt trên Máy Chủ

Trong quá trình SSR, mỗi URL yêu cầu tương ứng với một trạng thái mong muốn của ứng dụng chúng ta. Không có tương tác người dùng và không có cập nhật DOM, nên tính linh hoạt không cần thiết trên máy chủ. Theo mặc định, tính linh hoạt được tắt trong quá trình SSR để cải thiện hiệu suất.

Hooks Vòng Đời Của Component

Do không có cập nhật động, các hooks vòng đời như mountedonMounted hoặc updatedonUpdated KHÔNG được gọi trong quá trình SSR và chỉ được thực thi trên máy khách. Các hooks chỉ được gọi trong quá trình SSR là beforeCreatecreated

Bạn nên tránh mã tạo ra các tác động phụ cần dọn dẹp trong beforeCreatecreatedsetup() hoặc phạm vi gốc của <script setup>. Một ví dụ về các tác động phụ như vậy là thiết lập timers với setInterval. Trong mã chỉ chạy trên máy khách, chúng ta có thể thiết lập một bộ hẹn giờ và sau đó hủy nó trong beforeUnmountonBeforeUnmount hoặc unmountedonUnmounted. Tuy nhiên, vì hooks unmount sẽ không bao giờ được gọi trong quá trình SSR, các bộ hẹn giờ sẽ tồn tại mãi mãi. Để tránh điều này, hãy chuyển mã tác động phụ của bạn vào mountedonMounted.

Truy Cập Đến APIs Đặc Thù Platform

Mã chung không thể giả định truy cập đến các APIs đặc thù của nền tảng, vì vậy nếu mã của bạn trực tiếp sử dụng các toàn cục chỉ có trong trình duyệt như window hoặc document, chúng sẽ tạo ra lỗi khi thực thi trong Node.js, và ngược lại.

Đối với các nhiệm vụ được chia sẻ giữa máy chủ và máy khách nhưng với các APIs nền tảng khác nhau, khuyến khích là bọc các triển khai đặc thù của nền tảng bên trong một API chung, hoặc sử dụng các thư viện làm điều này cho bạn. Ví dụ, bạn có thể sử dụng node-fetch để sử dụng cùng một API fetch trên cả máy chủ và máy khách.

Đối với APIs chỉ có trong trình duyệt, phương pháp phổ biến là truy cập chúng lười biếng bên trong các hooks chỉ chạy trên máy khách như mountedonMounted.

Lưu ý rằng nếu một thư viện của bên thứ ba không được viết với tâm trạng sử dụng chung, có thể khá khó để tích hợp nó vào ứng dụng được k-render trên máy chủ. Bạn có thể có thể làm cho nó hoạt động bằng cách giả mạo một số toàn cục, nhưng điều này sẽ là một biện pháp tạm thời và có thể gây xáo lộn với mã nhận diện môi trường của các thư viện khác.

Ô Nhiễm Trạng Thái Xuyên Yêu Cầu

Trong chương quản lý trạng thái, chúng ta giới thiệu một [mô hình quản lý tr

ạng thái đơn giản sử dụng APIs Reactivity](state-management#simple-state-management-with-reactivity-api). Trong ngữ cảnh SSR, mô hình này đòi hỏi một số điều chỉnh bổ sung.

Mô hình tuyên bố trạng thái chia sẻ trong phạm vi gốc của một module JavaScript. Điều này làm cho chúng trở thành đối tượng duy nhất - tức là chỉ có một phiên bản của đối tượng phản ứng trong toàn bộ vòng đời của ứng dụng của chúng ta. Điều này hoạt động như mong đợi trong một ứng dụng Vue chỉ chạy trên máy khách thuần túy, vì module trong ứng dụng của chúng ta được khởi tạo lại cho mỗi lần truy cập trang của trình duyệt.

Tuy nhiên, trong ngữ cảnh SSR, các module ứng dụng thường chỉ được khởi tạo một lần trên máy chủ, khi máy chủ khởi động. Các phiên bản cùng một module sẽ được tái sử dụng qua nhiều yêu cầu máy chủ, và do đó cũng là các đối tượng trạng thái duy nhất của chúng tôi. Nếu chúng ta biến đổi trạng thái chia sẻ với dữ liệu cụ thể cho một người dùng, nó có thể bị rò rỉ ngẫu nhiên sang yêu cầu từ người dùng khác. Chúng ta gọi điều này là ô nhiễm trạng thái xuyên yêu cầu.

Chúng ta có thể kỹ thuật khả thi là khởi tạo lại tất cả các module JavaScript trên mỗi yêu cầu, giống như chúng ta làm trong trình duyệt. Tuy nhiên, việc khởi tạo các module JavaScript có thể tốn kém, vì vậy điều này sẽ ảnh hưởng đáng kể đến hiệu suất của máy chủ.

Giải pháp khuyến nghị là tạo một phiên bản mới của toàn bộ ứng dụng - bao gồm cả router và các cửa hàng toàn cầu - trên mỗi yêu cầu. Sau đó, thay vì nhập trực tiếp nó trong các thành phần của chúng tôi, chúng tôi cung cấp trạng thái chia sẻ bằng cách sử dụng provide cấp ứng dụng và tiêm nó vào các thành phần cần nó:

js
// app.js (chung giữa máy chủ và máy khách)
import { createSSRApp } from 'vue'
import { createStore } from './store.js'

// được gọi trên mỗi yêu cầu
export function createApp() {
  const app = createSSRApp(/* ... */)
  // tạo phiên bản mới của cửa hàng cho mỗi yêu cầu
  const store = createStore(/* ... */)
  // cung cấp cửa hàng ở cấp ứng dụng
  app.provide('store', store)
  // cũng tiết lộ cửa hàng cho mục đích hydrat hóa
  return { app, store }
}

Các thư viện quản lý trạng thái như Pinia được thiết kế với điều này trong tâm trí. Tham khảo hướng dẫn SSR của Pinia để biết thêm chi tiết.

Phù Hợp Hydration

Nếu cấu trúc DOM của HTML được k-render trước không khớp với đầu ra mong đợi của ứng dụng phía máy khách, sẽ xuất hiện một lỗi không phù hợp với hydration. Lỗi không phù hợp với hydration thường được giới thiệu bởi các nguyên nhân sau:

  1. Mẫu chứa cấu trúc lồng HTML không hợp lệ, và HTML được k-render đã "được sửa" bởi hành vi phân tích HTML tự nhiên của trình duyệt. Ví dụ, một nguy cơ phổ biến là <div> không thể được đặt bên trong <p>:

    html
    <p><div>hi</div></p>

    Nếu chúng ta tạo điều này trong HTML được k-render trước, trình duyệt sẽ kết thúc <p> đầu tiên khi gặp phần tử <div> và phân tích nó thành cấu trúc DOM sau:

    html
    <p></p>
    <div>hi</div>
    <p></p>
  2. Dữ liệu được sử dụng trong quá trình k-render chứa giá trị được tạo ngẫu nhiên. Vì ứng dụng cùng chạy hai lần - một lần trên máy chủ và một lần trên máy khách - giá trị ngẫu nhiên không đảm bảo sẽ giống nhau giữa hai lần chạy. Có hai cách để tránh không phù hợp do giá trị ngẫu nhiên:

    1. Sử dụng v-if + onMounted để k-render phần phụ thuộc vào giá trị ngẫu nhiên chỉ trên máy khách. Framework của bạn cũng có thể tích hợp các tính năng tích hợp sẵn, ví dụ như thành phần <ClientOnly> trong VitePress.

    2. Sử dụng thư viện tạo số ngẫu nhiên hỗ trợ tạo số với các hạt giống và đảm bảo rằng quá trình chạy trên máy chủ và quá trình chạy trên máy khách đều sử dụng cùng một hạt giống (ví dụ, bằng cách bao gồm hạt giống trong trạng thái được chuỗi hóa và lấy lại nó trên máy khách).

  3. Máy chủ và máy khách ở trong các múi giờ khác nhau. Đôi khi, chúng ta có thể muốn chuyển đổi một dấu thời gian thành thời gian địa phương của người dùng. Tuy nhiên, múi giờ trong quá trình chạy trên máy chủ và múi giờ trong quá trình chạy trên máy khách không phải lúc nào cũng giống nhau, và chúng ta có thể không biết đảm bảo múi giờ của người dùng đáng tin cậy trong quá trình chạy trên máy chủ. Trong những trường hợp như vậy, việc chuyển đổi thời gian địa phương cũng nên được thực hiện chỉ như một hoạt động trên máy khách.

Khi Vue gặp một lỗi không phù hợp với hydration, nó sẽ cố gắng tự động khôi phục và điều chỉnh DOM được k-render trước để phù hợp với trạng thái phía máy khách. Điều này sẽ dẫn đến mất hiệu suất k-render do các nút không chính xác bị loại bỏ và các nút mới được gắn kết, nhưng trong hầu hết các trường hợp, ứng dụng nên vẫn hoạt động như mong đợi. Tuy nhiên, vẫn tốt nhất là loại bỏ những lỗi không phù hợp với hydration trong quá trình phát triển.

Chỉ Thị Tùy Chỉnh

Vì hầu hết các chỉ thị tùy chỉnh liên quan đến việc thao tác trực tiếp trên DOM, chúng sẽ bị bỏ qua trong quá trình SSR. Tuy nhiên, nếu bạn muốn chỉ định cách một chỉ thị tùy chỉnh nên được k-render (tức là thêm vào phần tử được k-render những thuộc tính gì), bạn có thể sử dụng hook chỉ thị getSSRProps:

js
const myDirective = {
  mounted(el, binding) {
    // Triển khai phía máy khách:
    // Cập nhật trực tiếp DOM
    el.id = binding.value
  },
  getSSRProps(binding) {
    // Triển khai phía máy chủ:
    // Trả về các thuộc tính để k-render.
    // getSSRProps chỉ nhận chiều ràng buộc chỉ thị.
    return {
      id: binding.value
    }
  }
}

Teleports

Teleports đòi hỏi xử lý đặc biệt trong quá trình SSR. Nếu ứng dụng được k-render chứa Teleports, nội dung được teleport sẽ không thuộc phần chuỗi được k-render. Một giải pháp dễ dàng hơn là k-render

Teleport một cách điều kiện khi được mount.

Nếu bạn thực sự cần hydrate nội dung được teleport, chúng được mở ra dưới thuộc tính teleports của đối tượng ngữ cảnh ssr:

js
const ctx = {}
const html = await renderToString(app, ctx)

console.log(ctx.teleports) // { '#teleported': 'teleported content' }

Bạn cần tiêm vào đoạn mã teleport vào vị trí chính xác trong HTML trang cuối cùng của bạn giống như cách bạn cần tiêm vào đoạn mã ứng dụng chính.

TIP

Tránh nhắm mục tiêu vào body khi sử dụng Teleports và SSR cùng nhau - thông thường, <body> sẽ chứa nội dung được k-render từ máy chủ làm cho không thể xác định vị trí bắt đầu đúng cho hydration của Teleports.

Thay vào đó, ưu tiên một container riêng, ví dụ như <div id="teleported"></div> chỉ chứa nội dung được teleport.

Server-Side Rendering (SSR) has loaded