一文讀懂 Nuxt.js 服務端組件
服務端組件在 Web 開發生態系統中變得越來越普遍。傳統上,在單頁面應用中,即使是服務端渲染的應用,服務端僅與第一次加載相關,之后將由客戶端接管。這意味著 Web 應用的每個部分都必須能夠在客戶端和服務端上渲染。
相反,服務端組件允許在客戶端應用程序中對單個組件進行服務端渲染。即使需要生成靜態站點,也可以在 Nuxt 中使用服務端組件。這使得構建混合動態組件、服務端渲染的 HTML 甚至靜態標記塊的復雜站點成為可能。
事實上,Nuxt 在 React 之前就已經擁有了服務端組件功能。
1、主要優點Summer IS HERE
服務端組件允許從客戶端包中提取邏輯
通過將代碼移至服務端組件中,這些組件(以及它們使用的組件)不再需要由 Vue 進行水合或“跟蹤”。這對于可能不需要在客戶端上“重新運行”的復雜或昂貴的操作特別有用,例如應用語法高亮顯示或解析 markdown。
在大多數情況下,在 Nuxt 站點中使用服務端組件并不是一個萬能的解決方案。相反,當在客戶端上渲染組件所需的代碼量過多時,這將是一個有用的選項。
服務端組件確保特權代碼安全運行
當應用邏輯需要訪問數據庫、需要私鑰或密鑰時,服務端組件可以是一個有用的解決方案。它們是區分關注點的一種方式。(注意,還存在其他更好的替代方案,比如將僅限于服務端的代碼移入Nitro 服務端路由中,然后由組件進行“獲取”)
服務端組件在運行時不一定需要服務器
默認情況下,Nuxt 將預渲染應用中使用的服務端組件。只要渲染了應用的每個頁面,并且不只在客戶端加載它們,也不在運行時更改 props,服務端組件在完全靜態的網站上同樣適用。
這意味著可以在靜態托管上使用服務端組件,而無需更新到 serverless / edge 渲染。
如果啟用了有效載荷提取(在生成/靜態站點中默認啟用,也可以用于混合部署),那么Nuxt甚至會預取在可能導航到的頁面中使用的服務端組件,這樣它們將立即加載。
服務端組件可以與普通組件互換
服務端組件可以支持普通組件的所有功能,包括共享狀態、訪問當前路由等。因為它們的行為就像普通組件一樣,所以可以將它們嵌套在服務端組件中,或者將它們零散地分布在其他代碼中。
默認情況下,所有插件都將在渲染服務端組件時運行,除非在定義組件時通過設置island: false來明確禁用它們(即將推出的功能)。
2、相似但不同Summer IS HERE
還有其他聽起來類似的術語值得一提:
- React 服務端組件(RSC):這是一種完全不同的渲染服務端組件的方法,通常與從服務端到客戶端的流響應相關聯。
- “島嶼”架構: 由 Katie Sylor-Miller 命名,最近因 ?les 或 Astro 等框架而流行,這是一種將動態“島嶼”嵌入到更靜態的環境中的架構。Nuxt 方法則相反:將靜態“島嶼”嵌入到動態 Nuxt 應用中。
3、使用服務端組件Summer IS HERE
那么,如何使用服務端組件呢?
首先,需要啟用該功能(因為目前仍處于實驗階段):
// NUXT.CONFIG.TS
export default defineNuxtConfig({
experimental: {
componentIslands: true,
}
})
然后,只需添加 .server.vue 后綴即可將組件“轉換”為服務端組件。例如,這是網站頁腳的一個版本:
// COMPONENTS/THE-SITE-FOOTER.SERVER.VUE
<script lang="ts" setup>
const links = [
{
name: 'GitHub',
icon: 'i-ri:github-fill',
link: 'https://github.com/',
},
// ...
]
const year = new Date().getFullYear()
</script>
<template>
<div>
<footer>
<small> ? 2020-{{ year }} Github. </small>
<ul>
<li v-for="{ link, name, icon } in links">
<a :href="link" rel="me">
<span class="h-4 w-4 fill-current" :class="icon" alt="" />
<span class="sr-only">
{{ name }}
</span>
</a>
</li>
</ul>
</footer>
</div>
</template>
這些內容都是靜態的,所以非常適合適合使用服務端組件來實現。只需要在文件名后面添加.server
后綴就可以了,而使用的方式與以前完全相同。
<template>
<div>
<LayoutTheSiteHeader />
<NuxtPage />
<LayoutTheSiteFooter />
</div>
</template>
4、案例:Nuxt Content Summer IS HERE
一個有趣的用例就是創建一個服務端組件,它簡單地渲染一個 Nuxt content 頁面。假設已經安裝了 @nuxt/content,這個神奇的組件就可以將任何路由作為服務端組件進行渲染。
// COMPONENTS/STATIC-MARKDOWN-RENDER.SERVER.VUE
import { h } from 'vue'
import { ContentRendererMarkdown } from '#components'
export default defineComponent({
props: {
path: String,
},
async setup(props) {
if (process.dev) {
const { data } = await useAsyncData(() =>
queryContent(props.path!).findOne()
)
return () => h(ContentRendererMarkdown, { value: data.value! })
}
const value = await queryContent(props.path!).findOne()
return () => h(ContentRendererMarkdown, { value })
},
})
然后,這樣來使用它:
<template>
<StaticMarkdownRender path="/" />
</template>
目前, <NuxtLink> 組件不是交互式的,這意味著可能需要在父頁面中添加一些類似這樣的代碼,作為客戶端路由的“假裝”版本:
import { parseURL } from 'ufo'
function handleNavigationClicks(e: MouseEvent | KeyboardEvent) {
const anchor = (e.target as HTMLElement).closest('a')
if (anchor) {
const href = anchor.getAttribute('href')
if (href) {
e.preventDefault()
const url = parseURL(href)
if (!url.host || url.host === 'roe.dev') {
return navigateTo(url.pathname)
}
return navigateTo(href, { external: true })
}
}
}
5、路線圖Summer IS HERE
下面是 Nuxt 服務端組件的路線圖:
- 遠程數據源:很快就可以從其他網站加載服務端組件,能夠創建在不同網站中使用的 Nuxt 微服務來渲染組件。
- '懶加載' 服務端組件:很快就可以在服務端組件加載時顯示“回退”內容,以避免阻塞導航。
- 互動島嶼:已經可以在服務端組件內使用互動客戶端插槽,但很快將支持在服務端組件 HTML 中使用任意互動組件。
- ServerOnly:支持 <ServerOnly> 組件可能會很好,該組件可以自動將標記部分轉換為在服務端上渲染的僅服務端部分。