前端技術日新月異,最初的靜態網站逐漸被由服務端生成的網站所取代,后來又逐漸向客戶端渲染的應用轉變。不過客戶端渲染也存在一些問題,如加載時間變長和搜索引擎優化難度等。Astro 這個新的前端框架結合了服務端渲染和客戶端渲染的優點,可以更好地解決這些問題。
本文就來介紹一下這兩年爆火的前端框架 Astro,它在兩年的時間新增了 30k+ star:
這個前端框架,有點不一樣。
Astro 是一個開源的 JavaScript 框架,用于在流行的UI框架(如React、Preact、Vue 或 Svelte)之上生成 Web 應用。Astro 的頁面由多個獨立的組件組成。為了提高加載速度,Astro 會在服務端對頁面進行預渲染,并剝離所有 JavaScript,除非將某個組件標記為交互式,此時 Astro 將發送必要的最小量 JavaScript 以實現交互功能。
通過這種策略,Astro 頁面加載速度快,因為在首次渲染時不需要執行任何 JavaScript。在注水的過程中,Astro會將 JavaScript “注入”到組件中,使它們變成動態的。
Astro 是由 Fred Schott 和 Nate Moore 創建,最初用于構建快速靜態內容站點,如博客和落地頁等。它最初的獨特優勢就是簡單易用。可以從各種來源獲取內容,包括 API、CMS、MDX 文件或 Markdown 文件,并在 Astro 站點上展示。
Astro 最初的設計并非與 React 或 Vue 等競爭,而是為了支持互操作性。簡而言之,就是可以在 Astro 中使用喜歡的工具!它提供了對 React、Vue、Svelte 和 Tailwind CSS 等前端工具的一流支持。
然而,Astro 真正的亮點是名為島嶼的前端架構范式轉變。Astro的島嶼架構能夠提高應用的速度,它將 UI 拆分為更小的、隔離的組件,并在靜態頁面中部分啟動交互式組件,這是一個大膽的創新。
現在,Astro 已經發展成一個現代 Web 框架,可用于構建快速的多頁面應用、動態服務器端點和注重內容性能的網站。盡管保留了簡單性和核心功能,如服務器端點、內容集合、視圖過渡以及出色的開發者體驗,但 Astro 正不斷演進,成為一個功能強大的現代Web應用程序框架。
Astro 的核心是其島嶼架構。那么 Astro 中的島嶼是如何運作的呢?這就不得不說它的島嶼架構和部分水合了。
我們知道,客戶端和服務端是向用戶提供應用的兩個主要參與者:
下面來看一個在客戶端上重新水合的服務端渲染的應用的例子。
服務端渲染簡化的過程如下:
這是描述部分水合作用的簡單方法。我們沒有對整個應用進行水合處理,而是專注于應用的較小交互部分并獨立地對這些部分進行水合處理:
Astro 島嶼就是嵌入靜態HTML頁面中的交互式UI組件。一個頁面上可以存在多個島。每個島都是通過獨立的部分水合方式進行渲染。也就是說,每個島都是獨立水合的。
那這么做有什么好處呢?
通過利用島嶼,Astro 應用可以具有出色的初始加載時間,而不會受到 JavaScript 的限制。大部分站點保持靜態狀態,只有在初始頁面加載之后需要時才會對交互部分或島進行水合。
上面介紹了Astro 的島嶼架構和部分水合,下面來看看 Astro 的核心功能,以更有效的使用它。
Astro 應用的最小單位是組件。組件構成了每個 Astro 應用的基礎:
Astro 組件文件都以 .astro 結尾。
與大多數其他前端框架類似,組件內的抽象程度由開發者自己決定。例如,組件可以是 UI 的一小部分可重用的組件,例如頁眉或頁腳,或者組件可以足夠大以構成整個頁面或布局。
來看看下面的 Hello World Astro 組件:
// HelloWorld.astro ---const name = "前端充電寶"---<h1>Hello world, {name} </h1>
可以看到,Astro 包含兩個部分:組件腳本和組件模板
組件腳本是包含在 ---
虛線之間的部分,與 Markdown 前面的內容塊相同。在腳本部分中,默認情況下,可以編寫任何有效的 JavaScript 和 TypeScript!在上面的例子中,定義了一個 name
變量:
---const name = "前端充電寶"---
組件模板就是定義組件 HTML 的地方。如果組件需要向瀏覽器渲染一些 UI 元素或 HTML,可以在此處定義它。在上面的例子中,定義了以下內容:
<h1>Hello world, {name} </h1>
Astro 組件模板決定了組件的 HTML 輸出并支持純 HTML!不過,Astro 組件模板語法是 HTML 的超集。它添加了強大的插值功能,因此可以充分利用 JavaScript 和 TypeScript 來編寫組件模板。
除了簡單的字符串插值之外,組件模板語法還支持很多功能,例如添加<style>
和<script>
標簽、利用動態屬性、條件渲染、動態HTML等。以下是其中一些功能的演示:
---const isActive = false ---<h1>前端充電寶</h1>{/** 條件渲染 **/}{isActive && <p>Hello World from 前端充電寶</p>}{/** 樣式:默認情況下樣式是有作用域的 **/}<style> h1 { color: red, }{/** 添加腳本 **/}<script><!-- 也可以在此處編寫TypeScript。Astro 原生支持 TypeScript -->const header = document.querySelector("h1")header.textContent = "Updated LogRocket Header"</script>
Astro 應用的入口點是頁面,它利用基于文件的路由方式來管理頁面。
假設正在構建一個具有兩個不同路由的 Web 應用:index.html 和 about.html,那該如何表示呢?
Astro 項目的 src/pages/ 子目錄中的每個文件對應一個頁面。在這個例子中,需要兩個頁面 :src/pages/index.astro 和 src/pages/about.astro:
在構建應用時,可以通過像npm build這樣的簡單命令來進行構建,index.astro和about.astro將被構建成應用中相應的index.html和about.html文件。
Astro 是一個多頁面 Web 框架。也就是說,默認情況下,每個路由都對應一個單獨的 HTML 文檔。
可以按照以下步驟來嘗試使用 Astro:
在 Astro 中,不僅可以使用 .astro 組件作為頁面,還可以使用以下方式構建頁面:
上面我們討論了頁面和 HTML 輸出之間的一對一映射,不過,在 Astro 中也可以通過一個頁面處理多個路由。
Astro 頁面可以在文件名中指定動態路由參數,這將生成多個匹配的頁面。例如,構建一個博客應用,其中每篇博客都有自己的路由,可以通過以下方式表示該頁面:
src/pages/blogs/[blog].astro
注意,組件文件名中的方括號:[blog].astro。在靜態模式下,所有路由都必須在構建時確定。因此,動態路由必須導出 getStaticPaths() 方法,該方法返回具有 params 屬性的對象數組。這告訴 Astro 在構建時生成哪些頁面。
例如:
// src/pages/blogs/[blog.astro]---export function getStaticPaths() { return [ {params: {blog: "how-to-learn-astro"}}, {params: {blog: "how-to-learn-ai"}}, {params: {blog: "how-to-learn-astro-ai"}}, ]}// 可以從 Astro 全局對象中解構參數const { blog } = Astro.params --- <h1> Hello Blog, {blog} </h1>
當構建此應用時,src/pages/blogs/[blog.astro] 將生成三個博客頁面:
Astro 還支持服務端渲染,在這種情況下,路由是在運行時而不是構建時生成的。這意味著不需要指定 getStaticPaths() 方法,并且頁面可以大大簡化,如下所示:
// src/pages/blogs/[blog.astro]---// 可以從 Astro 全局對象中解構參數const { blog } = Astro.params --- <h1> Hello Blog, {blog} </h1>
在實踐中,使用SSR,這里的博客參數很可能是博客的唯一標識符,例如 ID。當用戶嘗試查看 /blogs/id 時,可以通過 Astro.params 獲取 id 并在服務端獲取所需的博客內容。
除了正常的組件和特殊的組件“頁面”,下面來了解另一種類型的組件:布局。
大多數 Web 應用都包含一些可重用的結構,這些結構為頁面提供了結構,例如頁眉、頁腳和側面導航元素。這些可以被抽象為可重用的 Astro 組件,稱為布局。
可以通過在 src/layouts 目錄中添加 Astro 組件來創建布局組件:
在布局組件中,可以抽象公共組件并在任意應用頁面中重用它們。
來看下面的布局組件:
// src/layouts/Main.astro---const { title } = Astro.props;---<!doctype html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="description" content="Astro description" /> <meta name="viewport" content="width=device-width" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="generator" content={Astro.generator} /> <title>{title}</title> </head> <body> {/** 注意,下面使用了 <slot/> 標簽 **/} <slot /> </body></html>
可以在任何頁面中使用此組件:
---import Main from '../layouts/Main.astro';---{/** 像渲染HTML元素一樣渲染 Main 組件:<Main></Main> **/}<Main title="Home page."> <main> <h1> Hello world, again </h1> <main></Main>
注意這里是如何使用布局組件的。在頁面組件的 HTML 部分中,渲染了布局組件,并將頁面的元素作為子元素傳遞給了<Main>組件。
可以通過在<Main>組件中添加一個<slot/>來渲染這個內容。簡而言之,每個傳遞給<Main>布局組件的子元素都將被渲染到<Main>中的<slot/>中:
還可以通過提供 props 來提高 Astro 組件的可重用性。例如:
<Main title="Hello world" /><Main title="Another title" /><Main title="Hello again" />
上面的例子就是在布局組件渲染時將不同的標題傳遞給它:
// src/layouts/Main.astro---const { title } = Astro.props;---<h1>{title} </h1>
Astro 在過去幾年中的增長很大程度上歸功于它的易于采用和開發。Astro 通過提供多樣化的模板,為工開發者快速啟動項目并編寫更少的代碼提供了極大的便利。
中間件在幫助 Astro 轉變為成熟的 Web 框架的過程中發揮了重要作用。
大多數全棧 Web 框架都有中間件實現,例如 NestJS。中間件位于客戶端請求和服務器應用邏輯的其余部分之間,起到中心化邏輯的作用,例如身份驗證、日志記錄、特性標志等。
Astro 也提供了中間件,下面是 Astro 中基本中間件的結構:
// src/middleware.js|tsimport { defineMiddleware } from "astro/middleware";const middleware = defineMiddleware((context, next) => { // 在這里對請求進行一些操作 return next() // 不進行任何操作,原樣轉發請求});export const onRequest = middleware;
為了類型安全,可以從 Astro 包中導入 MiddlewareResponseHandler 類型以及 defineMiddleware 實用程序。然后,通過 defineMiddleware 實用程序定義中間件變量:
const middleware = definedMiddleware(...)
最后,導出一個指向middleware的onRequest函數。
export const onRequest = defineMiddleware(...)
假設你正在構建一個大型的內容驅動應用,這樣的項目預計會使用大量的Markdown、MDX、JSON或YAML文件。
組織項目內容的最佳實踐是將內容數據保存在數據庫中,可以在數據庫中驗證文檔結構并確保所需的內容符合我們想要的數據模型。
使用此解決方案時,可以將它們表示為存儲在具有預定義架構的數據庫中的數據集合:
在大多數靜態站點生成器中,驗證本地模式是很困難的。Astro 通過其 Content Collections API (內容集合)提供了強類型安全性,改變了這種情況。
內容集合是 Astro 項目的 src/content 文件夾中的任何頂級目錄:
集合中的單個文檔被稱為集合項:
以這種方式組織大型內容驅動的網站的好處在于,可以利用Astro的類型安全性來查詢和處理內容集合。例如,可以為內容集合引入一個模式,如下所示:
//
本文鏈接:http://www.www897cc.com/showinfo-26-31991-0.htmlAstro,這個前端框架有點不一樣!
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com