最近有很多開發者宣佈他們已經將網站遷移到Astro。這通常伴隨著一張接近完美的Lighthouse分數的截圖和一系列火箭表情符號。
像大多數人一樣,我發現無休止的新框架會讓人感到厭倦。但我對Astro做了一些研究,認為它真的值得一試。
在本文中,我將向您展示如何使用 Astro 構建基於 Vue 的應用程式,我們將瞭解其獨特的架構如何帶來比單頁應用程式 (SPA) 更好的效能。
SPA 架構回顧
在我們看到 Astro 的實際應用之前,我們需要了解它的架構。為此,讓我們首先提醒自己單頁應用架構的優缺點。
SPA 將網站的所有功能和內容抽象為 JavaScript 元件。這很棒,因為它使網站的開發變得容易。
這種方法的缺點是當網站投入生產時。所有這些JavaScript元件被捆綁在一起成為一個大的應用程式。由於體積太大,瀏覽器下載和執行的速度可能會很慢。
當然,你可以通過程式碼拆分來優化這個捆綁。但是,瀏覽器仍然會有一些前期成本必須支付,只是為了啟動網站。
<!-- 典型的 SPA 頁面 -->
<head>
<script src="/app.js"></script>
</head>
<body>
<!-- 在 app.js 載入之前,此頁面沒有有意義的內容 -->
<div id="app"></div>
</body>
Islands architecture
Islands架構,Astro使用的架構,也使用了元件。然而,與單頁應用程式不同的是,這些元件並沒有捆綁到一個 JavaScript 包中。
相反,每個元件都被視為一個獨立的迷你應用程式,與所有其他元件隔離存在。
例如,如果您的頁面有一個基於 JavaScript 的導航欄,那將是一個迷你應用程式。如果它還具有 JavaScript 驅動的影像輪播,那就是另一個迷你應用程式。等等。
但是,如果這些元件沒有被捆綁,它們如何被包含在專案中?我將在下一節解釋這個問題。
<!-- Islands architecture -->
<body>
<MyNavBar /> <!-- navbar mini app -->
<main>
<MyCarousel /> <!-- carousel mini app -->
<div class="content">
<!-- more page content... -->
</div>
</main>
</body>
伺服器渲染的元件
Astro 主要是一個靜態站點生成器。它適用於大多數支援伺服器渲染元件的 UI 庫,包括 Vue、Svelte、Preact、React 和 Lit。
因此,當Astro構建你的應用程式時,每個JavaScript元件都在伺服器端載入,內容是”快照“。這個快照被新增到靜態頁面上。
伺服器渲染不是 Astro 特有的功能,但在 SPA 中這是一個可選功能,而在 Astro 中,這是一個至關重要的功能,我們將在下面看到。
<!-- 開發內容 -->
<body>
<MyForm /> <!-- JS component -->
</body>
<!-- 快照內容 -->
<body>
<form> <!-- Server rendered JS component -->
<input type="text" >
<!-- ... -->
</form>
</body>
Progressive hydration
這就是Astro的神奇之處——通過islands架構、伺服器渲染元件和漸進式水合的組合。
由於我們的頁面被劃分為伺服器渲染的迷你應用程式,互動層(JS)可以獨立載入,並且只在需要的時候載入。
例如,您可能有一個互動式表單。此表單位於頁面下方,位於視口之外。
表單是伺服器渲染的,所以我們在頁面上看到它。但是,在使用者將其滾動到檢視中之前,不需要載入昂貴的 JavaScript。
這就是 Astro 中“漸進式水合作用”的含義——我們只在需要時載入 JavaScript。
建立一個 Vue + Astro 專案
現在理論已經講完了,讓我們來看看它的實際效果吧!
要開始建立 Astro 專案,我們將首先建立一個目錄:
$ mkdir vue-astro
然後執行 Astro 安裝嚮導:
$ npm init astro
安裝嚮導將允許我們選擇“Vue”作為我們選擇的框架。這將建立一個包含 Vue 元件的樣板專案。
Astro元件
Astro 頁面儲存在 src/pages 目錄中。在預設安裝中,我們看到一個檔案 index.astro,如下所示。
src/pages/index.astro
---
import VueCounter from '../components/VueCounter.vue';
let title = 'My Astro Site';
---
<html lang="en">
<head>
<!-- ... -->
<title>{title}</title>
</head>
<body>
<main>
<!-- ... -->
<VueCounter client:visible />
</main>
</body>
</html>
Astro 具有單檔案元件樣式,與 Vue 類似,但有一些重要區別。
首先,在檔案的頂部,我們看到似乎是前端內容,即用 ---
劃定的內容。這是在伺服器端執行的JavaScript。這不會被髮送到客戶端。
在這裡我們可以看到兩件重要的事情:首先,我們正在匯入一個Vue元件(你可以從任何支援的框架中匯入元件)。另外,我們正在設定一個值:title
。
這裡宣告的所有變數在模板中都是可用的。你會注意到 title
在模板中以類似JSX的語法進行插值。
src/pages/index.astro
---
...
let title = 'My Astro Site';
---
<html lang="en">
<head>
<!-- ... -->
<title>{title}</title>
</head>
<!-- ... -->
接下來,注意模板中宣告的元件。
預設情況下,元件在客戶端是不互動的,只是由Astro進行伺服器渲染。
如果我們想讓元件互動,即載入 JavaScript,我們需要給它一個指令告訴客戶端何時載入它。
在這種情況下,client:visible
指令告訴 Astro 當元件在頁面中可見時使 VueCounter
互動。
如果發生這種情況,Astro 將從伺服器請求該元件的 JS 並對其進行水合。
---
import VueCounter from '../components/VueCounter.vue';
...
---
<html lang="en">
<head><!-- ... --></head>
<body>
<main>
<!-- ... -->
<VueCounter client:visible />
</main>
</body>
</html>
載入Astro
現在讓我們執行 Astro 的開發伺服器來檢視我們的專案。
npm run dev
在頁面的原始碼中,你會看到在文件中沒有任何的JavaScript捆綁! 不過,我們確實看到了伺服器渲染的Vue元件。
我們還看到 Astro 在文件正文的底部新增了一個指令碼。在這裡,它載入了一個模組來水合 Vue 元件。
該模組將下載 Vue 元件和依賴項(Vue 框架),而不會阻塞渲染。
index.html
<!-- Page source -->
<body>
<!-- server rendered component -->
<div id="vue" class="counter">
<button>-</button>
<pre>0</pre>
<button>+</button>
</div>
<!-- 新增的程式碼片段以水合 Vue 元件 -->
<script type="module">
import setup from '/_astro_frontend/hydrate/visible.js';
// ...
</script>
為什麼 Vue + Astro 可能比 Vue SPA 更好
要了解為什麼 Astro 在 UX 方面可以擊敗單頁應用程式,讓我們對網站載入時發生的情況進行簡化分解。
- index.html已經載入。它沒有JS捆綁,但它包括你的伺服器渲染的元件,所以使用者已經可以看到你的網站內容--只是還沒有互動。
- 元件所需的任何JS現在將以一系列獨立指令碼的形式非同步下載。
- 下載這些指令碼後,它們將被解析並執行。現在可以進行互動了。
現在讓我們想象一下,我們把這個網站重新建成一個單頁的應用程式。它現在會如何載入?
- index.html被載入。由於該頁面不包含任何內容,使用者無法看到任何東西。瀏覽器將開始下載捆綁程式。
- 下載 JS 包後,瀏覽器就會對其進行解析。使用者仍然看不到任何東西。
- 一旦 JS 包被解析並執行,頁面內容就生成了。使用者現在可以檢視應用程式並與之互動。
簡單的說:Astro 網站幾乎可以立即提供可見的內容,不像 SPA 需要先下載並執行 JS 包。
(Astro應用也會稍早提供互動性,因為它可能不需要下載那麼多JS,因為沒有SPA外殼、路由器等)
最後的想法
Astro 的架構可能是比單頁應用程式更好的選擇,因為它無需 JavaScript 即可使內容可見,並且僅在需要時載入 JS。
從理論上講,單頁應用程式可以通過預渲染和程式碼拆分的組合來實現類似的效果。不同之處在於,Astro 網站預設以這種方式進行優化,因為您需要選擇加入互動性和 JS。
當然,並不是每個應用程式都會從這種架構中受益,因為 SPA 更適合某些型別的應用程式,例如高度動態和互動式的應用程式。所以我們不會期望 SPA 架構會消失。