透過 100 多個技巧的集合來學習 Nuxt!
文章·  

Nuxt on the Edge

了解我們如何讓 Nuxt 3 能夠在邊緣運行時環境中運行,以便在靠近您用戶的伺服器端進行渲染。

簡介

2017 年 9 月,Cloudflare 推出了 Cloudflare Workers,使其能夠在其邊緣網路上執行 JavaScript。這意味著您的程式碼將在大約 30 秒內部署到全球一百多個地點的整個邊緣網路。這項技術讓您可以專注於編寫靠近您用戶的應用程式,無論他們身在世界何處(約 50 毫秒的延遲)。

Worker 的運行時環境與 Node.js 或瀏覽器不同,它使用 Google Chrome 開發的 JavaScript 引擎 V8 執行程式碼。到目前為止,您可以在他們的平台上執行的只是在擊中您的伺服器之前在邊緣運行的腳本,以提高效能或根據請求標頭新增一些邏輯,例如。

2020 年 11 月,在開發 Nuxt 3 時,我們決定在邊緣運行時環境 / V8 隔離區中實際運行 Nuxt

當使用像 CloudFlare Workers 這樣的平台時,它解鎖了從世界各地以約 50 毫秒的速度進行伺服器端渲染頁面的能力,而無需處理伺服器、負載平衡器和快取,大約每百萬次請求 0.3 美元。截至今天,新的平台開始允許在 V8 隔離區上運行應用程式,例如 Deno Deploy。

2024 年更新:我發布了 NuxtHub,讓您可以在邊緣上使用 Nuxt,在您的 Cloudflare 帳戶上以零設定建構完整的堆疊應用程式。它包括資料庫、Blob 儲存、KV、遠端儲存等等。

挑戰

為了讓 Nuxt 在 Worker 中運行,我們必須重寫 Nuxt 的某些部分,使其與環境無關(在 Node.js、瀏覽器或 V8 中運行)。

我們從伺服器開始,並創建了 unjs/h3:一個為高效能和可移植性而建構的最小化 HTTP 框架。它取代了我們在 Nuxt 2 中使用的 Connect,但與它相容,因此您可以繼續使用 Connect/Express 中介軟體。在 Worker 中,對於每個傳入的請求,它都會在生產環境中啟動 Nuxt,將請求發送給它,然後發回回應。

在 Nuxt 2 中,在生產環境中於記憶體中啟動伺服器(也稱為冷啟動)的時間約為 300 毫秒,因為我們必須載入伺服器和應用程式的所有相依性才能處理請求。

透過開發 h3,我們決定對附加到伺服器的每個處理常式進行程式碼分割,並僅在請求時才延遲載入它們。當您啟動 Nuxt 3 時,我們僅在記憶體中載入 h3 和相應的處理常式。當請求傳入時,我們將載入與路由對應的處理常式並執行它。

透過採用這種方法,我們將冷啟動時間從約 300 毫秒縮短到約 2 毫秒

為了讓 Nuxt 在邊緣上運行,我們還有另一個挑戰:生產套件的大小。這包括伺服器、Vue 應用程式和 Node.js 相依性的組合。Cloudflare Workers 目前對 Worker 大小有限制:免費方案為 1MB,付費方案(每月 5 美元)為 5MB。

為了實現這一目標,我們創建了 unjs/nitro,我們的伺服器引擎,當運行 nuxt build 命令時,它會將整個專案打包並將所有相依性包含到最終輸出中。它使用 Rollupvercel/nft 來追蹤 node_modules 使用的程式碼,以移除不必要的程式碼。基本 Nuxt 3 應用程式的產生輸出總大小約為 700kB gzip。

最後,為了在開發(Node.js)和 Cloudflare 上的生產(邊緣運行時環境)之間提供相同的開發人員體驗,我們創建了 unjs/unenv:一個透過模擬或為已知相依性新增 Polyfill 來轉換 JavaScript 程式碼以在任何地方(與平台無關)執行的程式庫。

在 Nuxt,我們相信您應該有自由選擇最適合您的託管供應商。

這就是為什麼您可以在以下位置部署具有邊緣端渲染的 Nuxt 應用程式:

我們還支援許多其他部署供應商,包括靜態託管傳統 Node.js 無伺服器和伺服器主機

推動全堆疊功能

既然我們已經讓 Nuxt 在邊緣運行時環境中運行,我們可以做的不僅僅是渲染 Vue 應用程式。感謝伺服器目錄,創建 API 路由只需一個 TypeScript 檔案即可。

若要新增 /api/hello 路由,請建立 server/api/hello.ts 檔案

server/api/hello.ts
export default defineEventHandler((event) => {
  return {
    hello: 'world'
  }
})

您現在可以在您的頁面和元件中通用地呼叫此 API

pages/index.vue
<script setup>
const { data } = await useFetch('/api/hello')
</script>

<template>
  <pre>{{ data }}</pre>
</template>

當我們建立 useFetch$fetch 時,需要注意的一件重要事情是,在伺服器端渲染期間,如果您呼叫您的 API 路由,它將模擬請求並直接呼叫函數程式碼:避免 HTTP 請求並減少頁面渲染時間

在開發人員體驗方面,您會注意到,當建立伺服器檔案時,Nuxt 伺服器會繼續運行,而無需重建 Vue 應用程式。這是因為 Nuxt 3 在建立 API 和伺服器路由時支援熱模組替換 (HMR)。

此外,透過利用物件關聯對應 (ORM),例如 drizzle-orm,開發人員可以連接邊緣和無伺服器資料庫,例如 D1TursoNeonPlanetscale 等等。

我建立了 Atidone,一個開源的示範,展示了在邊緣上運行的具有身份驗證和資料庫的全堆疊應用程式。原始程式碼在 GitHub 上以 MIT 授權提供,網址為 atinux/atidone

結論

我們對邊緣端渲染及其解鎖的功能感到興奮。我們 Nuxt 團隊迫不及待地想看看您會在此基礎上建構什麼!

請隨時加入我們的 Discord 伺服器或在 Twitter 上提及 @nuxt_js 來分享您的作品。