我最近开始使用 Astro 来重建最初使用 WordPress、Go、Rails 和 Hugo 构建的副项目。我选择 Astro 是因为它具有类似 React 的 DX 和良好的语言服务器支持,并且它与具有慷慨免费套餐的无服务器托管平台(Cloudflare、AWS Lambda 等)兼容。
当我开始使用 Astro 时,我对它了解不多。现在我已经迁移了多个站点,我想与其他考虑使用该框架的人分享我喜欢和不喜欢该框架的地方。
Astro 的核心是一个静态站点生成器,能够在需要时生成动态服务器渲染页面。 Astro 非常适合互动性有限的博客或小型营销网站。该框架提供了 Next.js 的大部分 DX,而没有 React.js 开销。
说实话:传统的服务器渲染模板语言严重缺乏良好的语言服务器支持和代码格式。与 React/Vue/Svelte 同行相比,Go 模板、Jinja、ERB 和 EJS 在工具方面远远落后。大多数服务器渲染的模板语言无法知道哪些变量在范围内或者它们的类型是什么。
使用 Astro,所有这些功能都只需一个 VS Code 扩展即可实现。
在 Astro 模板内,您可以在模板顶部的“代码围栏”内设置数据,该代码围栏在构建时或响应服务器上的请求时运行。实际情况如下:
--- import Layout from "../layouts/Layout.astro"; import { getPosts } from "../data/posts"; const posts: { id, title }[] = await getPosts(); --- <Layout pageTitle="Posts"> <h1>Posts</h1> {post.length > 0 ? ( <ul> {posts.map((post) => ( <li> <a href={`/posts/${post.id}`}> {post.title} </a> </li> )} </ul> ) : null} </Layout>
由于模板的所有数据都加载到模板上方的“代码围栏”中,因此语言服务器可以为范围内定义的任何对象的属性提供自动完成功能。它还会指示您何时尝试使用不存在的变量。
我对 Go 模板、Jinja 和 EJS 等传统模板语言最大的抱怨之一是它们没有可以接受子元素的“组件”。我的大多数网站都有某种宽度受限的“容器”UI 元素,这可确保内容不会飞到超宽显示器上的屏幕末端。如果您有一个手动添加到
的 .container 类,元素,那么这通常可以正常工作。但是,如果您使用的是 Tailwind 这样的实用 CSS 框架,那么您可能会发现自己将以下代码添加到每个页面模板中:<div > <p>When you eventually need to change these classes, it's an error-prone pain to update each file manually. But if your templating language doesn't have components that can accept children, it's almost inevitable. </p> <p>Unlike those traditional templating languages, Astro templates can be used as components that accept children using a <slot /> tag. A long string of utility classes could be extracted into a reusable Astro component:<br> <pre class="brush:php;toolbar:false"><div > <p>The Astro component could then be consumed from another Astro file.<br> </p> <pre class="brush:php;toolbar:false">--- import Container from "../components/Container.astro"; --- <Container> <h1>Hello, world!</h1> </Container>
Astro 文件不限于单个插槽:它们可以有多个。
我最喜欢的 Astro 组件功能是它们可以接受代码围栏内的 props。这是一个例子:
--- import Layout from "../layouts/Layout.astro"; import { getPosts } from "../data/posts"; const posts: { id, title }[] = await getPosts(); --- <Layout pageTitle="Posts"> <h1>Posts</h1> {post.length > 0 ? ( <ul> {posts.map((post) => ( <li> <a href={`/posts/${post.id}`}> {post.title} </a> </li> )} </ul> ) : null} </Layout>
该组件可以在另一个文件中使用时接受道具。
<div > <p>When you eventually need to change these classes, it's an error-prone pain to update each file manually. But if your templating language doesn't have components that can accept children, it's almost inevitable. </p> <p>Unlike those traditional templating languages, Astro templates can be used as components that accept children using a <slot /> tag. A long string of utility classes could be extracted into a reusable Astro component:<br> <pre class="brush:php;toolbar:false"><div > <p>The Astro component could then be consumed from another Astro file.<br> </p> <pre class="brush:php;toolbar:false">--- import Container from "../components/Container.astro"; --- <Container> <h1>Hello, world!</h1> </Container>
我之前已经用 Vite 构建了自己的服务器端集成。如果您想快速在线获取某些东西,那么您希望避免自己构建这种商品功能。 Astro 是内置的。
如果您想向 Astro 页面或组件添加自定义脚本,您只需在页面上放置一个脚本标签即可。
--- type Props = { pageTitle: string; pageDescription: string }; const { pageTitle, pageDescription } = Astro.props; --- <!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>{pageTitle}</title> <meta name="description" content={pageDescription} /> </head> <body> <slot /> </body> </html>
Astro 将自动编译 TS 和 JS 文件作为站点构建过程的一部分。您还可以编写使用 Astro 组件内脚本标记内的 node_modules 导入的脚本,Astro 将在构建时对其进行编译并将其提取到自己的文件中。
--- import Layout from "../layouts/Layout.astro"; --- <Layout pageTitle="Tyler's Blog" pageDescription="I don't really post on here." > <h1>Tyler's blog</h1> <p>Sorry, there's no content yet...</p> </Layout>
您可以通过在代码围栏中导入 CSS 或 Scss 样式来将 CSS 或 Scss 样式包含在 Astro 文件中。
<div> <h1>This is my page</h1> <script src="../assets/script.ts"></script> </div>
Astro 还提供了通过在 Astro 文件中使用样式标签来执行 范围样式 的功能。这个功能对于 Vue 用户来说可能很熟悉。
给定以下 Astro 文件:
<script> // This will also compile down to a JavaScript file at build time. import axios, { type AxiosRequestConfig, type AxiosResponse } from "axios"; const response = await axios .get<AxiosRequestConfig, AxiosResponse<{foo: string}>>("/some-endpoint"); console.log(response.data.foo); </script>
简单吧?
操作提供了一种类型安全的方式来运行后端函数。它们提供验证并可以处理 JSON 和表单数据。它们无疑是 Astro 的杀手级功能之一:所有这些都需要以定制方式在 Next.js 应用程序中手动连接。它们需要的代码比示例多一些,但使用起来非常优雅。我建议阅读操作文档页面。
有无数的 Twitter 开发者说 React “足够快”。对于很多事情来说并非如此。
我在小项目中使用 Rasbperry Pi 4,你可以感受 React 的运行时成本。我确信对于便宜的 Android 手机来说也是一样的,只不过在这种情况下 JS 开销也会耗尽电池。
如果我的网站需要的唯一交互性是切换导航菜单,我宁愿自己连接它。当我需要时,我会很乐意使用 React,但对于很多项目来说,我实际上并不需要它。
我不喜欢 Astro 的地方并不是该框架独有的:它们是从 JavaScript 生态系统中其他工具借用的想法。
由于 Astro 采用基于文件的路由,Astro 项目中的一半文件最终命名为 index.(astro|js|ts) 或 [id].(astro|js|ts)。基于文件的路由是一种令人讨厌的模式,在 Next.js 实现它之后,它席卷了前端世界,并且它有很多缺点:
我承认:当您创建一个页面少于 10 个的网站时,基于文件的路由感觉很棒。但随着网站的发展,它会增加摩擦,你与该功能的对抗多于从中受益。
在 JavaScript 生态系统中,Remix 通过提供基于文件的路由版本而脱颖而出,该版本将所有路由扁平化到单个目录中,并允许用户通过手动路由配置完全选择退出基于文件的路由。
基于文件的路由是我对 Astro 最大的抱怨,但这是一个很难逃避的功能。它在 Next.js、Nuxt.js、SvelteKit 等中实现。更奇怪的是,这些框架对于应用程序其他部分的文件名基本上没有意见。与 Ruby on Rails 相比,大多数 JavaScript 框架在文件名和项目结构方面都为您提供了很大的自由度——除了用于路由。这是一种特殊情况,特殊情况会增加软件的复杂性。
我真正喜欢的 JavaScript 语言功能是能够在单个文件中定义多个变量、函数和类。这使得可以轻松地共置相关功能,而不必因为语言级别的限制而提前将其提取到其他文件。
与 Vue 的单文件组件非常相似,Astro 文件允许为每个文件定义一个组件。这对我来说很乏味,但 Astro 提供了一种解决方法。
Astro 可以将预渲染的 React、Vue、Svelte、Solid 和 Preact 组件直接嵌入到其模板中,而无需加载任何客户端 JavaScript。 Preact 组件与 Astro 合理地配对得很好,因为 Preact JSX 比 React JSX 更接近 HTML。不过,在同一个项目中管理 Astro 和 Preact 组件确实变得很尴尬,一旦我开始使用 Preact 组件,我发现自己将大部分 UI 从 Astro 文件移到了 Preact 中。
如果您是 Next.js、Nuxt 或 SvelteKit 的狂热用户,并且对您的框架感到满意,那么您可能不会从 Astro 中得到太多好处。然而,如果您想向用户减少 JavaScript 的臃肿,同时保留 Next.js 之类的 DX,那么 Astro 可能适合您。
Astro 面向内容驱动的网站,并提供开箱即用的 Markdown 支持。由于其对内容的关注,它是替代 WordPress 或 Hugo 网站的理想开发者博客平台。然而,它的功能远不止通过操作等功能来实现内容网站。
尽管我非常厌恶基于文件的路由,但我对采用 Astro 最大的担忧是可能会发生重大变化,迫使我重建网站。 JavaScript 工具比其他语言生态系统中的工具更积极地进行重大更改。因为我对 Astro 还很陌生,所以我不知道从一个主要版本到下一个版本有多少变化。即使有这样的担忧,我还是计划将 5 到 6 个网站从其他平台迁移到 Astro,这样我就可以利用其一流的 DX 并以低廉的价格托管这些网站。
以上是对 Astro 的第一印象:我喜欢什么和不喜欢什么的详细内容。更多信息请关注PHP中文网其他相关文章!