一文讀懂 Nuxt.js 服務(wù)端組件
服務(wù)端組件在 Web 開發(fā)生態(tài)系統(tǒng)中變得越來越普遍。傳統(tǒng)上,在單頁面應(yīng)用中,即使是服務(wù)端渲染的應(yīng)用,服務(wù)端僅與第一次加載相關(guān),之后將由客戶端接管。這意味著 Web 應(yīng)用的每個(gè)部分都必須能夠在客戶端和服務(wù)端上渲染。
相反,服務(wù)端組件允許在客戶端應(yīng)用程序中對(duì)單個(gè)組件進(jìn)行服務(wù)端渲染。即使需要生成靜態(tài)站點(diǎn),也可以在 Nuxt 中使用服務(wù)端組件。這使得構(gòu)建混合動(dòng)態(tài)組件、服務(wù)端渲染的 HTML 甚至靜態(tài)標(biāo)記塊的復(fù)雜站點(diǎn)成為可能。
事實(shí)上,Nuxt 在 React 之前就已經(jīng)擁有了服務(wù)端組件功能。
1、主要優(yōu)點(diǎn)Summer IS HERE
服務(wù)端組件允許從客戶端包中提取邏輯
通過將代碼移至服務(wù)端組件中,這些組件(以及它們使用的組件)不再需要由 Vue 進(jìn)行水合或“跟蹤”。這對(duì)于可能不需要在客戶端上“重新運(yùn)行”的復(fù)雜或昂貴的操作特別有用,例如應(yīng)用語法高亮顯示或解析 markdown。
在大多數(shù)情況下,在 Nuxt 站點(diǎn)中使用服務(wù)端組件并不是一個(gè)萬能的解決方案。相反,當(dāng)在客戶端上渲染組件所需的代碼量過多時(shí),這將是一個(gè)有用的選項(xiàng)。
服務(wù)端組件確保特權(quán)代碼安全運(yùn)行
當(dāng)應(yīng)用邏輯需要訪問數(shù)據(jù)庫、需要私鑰或密鑰時(shí),服務(wù)端組件可以是一個(gè)有用的解決方案。它們是區(qū)分關(guān)注點(diǎn)的一種方式。(注意,還存在其他更好的替代方案,比如將僅限于服務(wù)端的代碼移入Nitro 服務(wù)端路由中,然后由組件進(jìn)行“獲取”)
服務(wù)端組件在運(yùn)行時(shí)不一定需要服務(wù)器
默認(rèn)情況下,Nuxt 將預(yù)渲染應(yīng)用中使用的服務(wù)端組件。只要渲染了應(yīng)用的每個(gè)頁面,并且不只在客戶端加載它們,也不在運(yùn)行時(shí)更改 props,服務(wù)端組件在完全靜態(tài)的網(wǎng)站上同樣適用。
這意味著可以在靜態(tài)托管上使用服務(wù)端組件,而無需更新到 serverless / edge 渲染。
如果啟用了有效載荷提?。ㄔ谏?靜態(tài)站點(diǎn)中默認(rèn)啟用,也可以用于混合部署),那么Nuxt甚至?xí)A(yù)取在可能導(dǎo)航到的頁面中使用的服務(wù)端組件,這樣它們將立即加載。
服務(wù)端組件可以與普通組件互換
服務(wù)端組件可以支持普通組件的所有功能,包括共享狀態(tài)、訪問當(dāng)前路由等。因?yàn)樗鼈兊男袨榫拖衿胀ńM件一樣,所以可以將它們嵌套在服務(wù)端組件中,或者將它們零散地分布在其他代碼中。
默認(rèn)情況下,所有插件都將在渲染服務(wù)端組件時(shí)運(yùn)行,除非在定義組件時(shí)通過設(shè)置island: false來明確禁用它們(即將推出的功能)。
2、相似但不同Summer IS HERE
還有其他聽起來類似的術(shù)語值得一提:
- React 服務(wù)端組件(RSC):這是一種完全不同的渲染服務(wù)端組件的方法,通常與從服務(wù)端到客戶端的流響應(yīng)相關(guān)聯(lián)。
- “島嶼”架構(gòu): 由 Katie Sylor-Miller 命名,最近因 ?les 或 Astro 等框架而流行,這是一種將動(dòng)態(tài)“島嶼”嵌入到更靜態(tài)的環(huán)境中的架構(gòu)。Nuxt 方法則相反:將靜態(tài)“島嶼”嵌入到動(dòng)態(tài) Nuxt 應(yīng)用中。
3、使用服務(wù)端組件Summer IS HERE
那么,如何使用服務(wù)端組件呢?
首先,需要啟用該功能(因?yàn)槟壳叭蕴幱趯?shí)驗(yàn)階段):
// NUXT.CONFIG.TS
export default defineNuxtConfig({
experimental: {
componentIslands: true,
}
})
然后,只需添加 .server.vue 后綴即可將組件“轉(zhuǎn)換”為服務(wù)端組件。例如,這是網(wǎng)站頁腳的一個(gè)版本:
// 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>
這些內(nèi)容都是靜態(tài)的,所以非常適合適合使用服務(wù)端組件來實(shí)現(xiàn)。只需要在文件名后面添加.server
后綴就可以了,而使用的方式與以前完全相同。
<template>
<div>
<LayoutTheSiteHeader />
<NuxtPage />
<LayoutTheSiteFooter />
</div>
</template>
4、案例:Nuxt Content Summer IS HERE
一個(gè)有趣的用例就是創(chuàng)建一個(gè)服務(wù)端組件,它簡(jiǎn)單地渲染一個(gè) Nuxt content 頁面。假設(shè)已經(jīng)安裝了 @nuxt/content,這個(gè)神奇的組件就可以將任何路由作為服務(wù)端組件進(jìn)行渲染。
// 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 服務(wù)端組件的路線圖:
- 遠(yuǎn)程數(shù)據(jù)源:很快就可以從其他網(wǎng)站加載服務(wù)端組件,能夠創(chuàng)建在不同網(wǎng)站中使用的 Nuxt 微服務(wù)來渲染組件。
- '懶加載' 服務(wù)端組件:很快就可以在服務(wù)端組件加載時(shí)顯示“回退”內(nèi)容,以避免阻塞導(dǎo)航。
- 互動(dòng)島嶼:已經(jīng)可以在服務(wù)端組件內(nèi)使用互動(dòng)客戶端插槽,但很快將支持在服務(wù)端組件 HTML 中使用任意互動(dòng)組件。
- ServerOnly:支持 <ServerOnly> 組件可能會(huì)很好,該組件可以自動(dòng)將標(biāo)記部分轉(zhuǎn)換為在服務(wù)端上渲染的僅服務(wù)端部分。