使用 Astro 构建网站初探

Avatar of Chris Coyier
Chris Coyier 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

Astro 是一个全新的网站构建框架。对我来说,**最棒的一点**是它允许您像使用 JavaScript 框架一样构建网站(实际上您也是在使用),但输出的是一个零 JavaScript 静态网站。您可以根据需要选择加入客户端 JavaScript,并且有一些巧妙的方法可以做到这一点。值得注意的是,由于它支持您可能已经熟悉的组件:React/Preact (JSX)、Svelte、Vue 或 Web Components,因此学习曲线有所降低。

基本功能

启动新项目应该像预期一样简单

npm init astro
npm install
npm start

有一个有用的流程和输出

正如预期的那样(就像您在使用 Next 或 Nuxt 或任何其他网站构建器类型的项目时获得的那样),您会在本地端口获得一个可以立即启动的开发服务器

从这里开始,我认为基本功能包括 CSS 注入/热模块替换。这方面不用担心

一个拥有真正组件的静态网站生成器

这对我来说是一件非常棒的事情。我真的很喜欢静态网站生成器的理念——我认为它们在很多情况下都很有意义。通过网络发送 HTML 对于弹性、CDN 效率、SEO、可访问性等都是一个好举措。但在过去,许多选项要么是

  • 一个由 JavaScript 驱动的静态网站生成器,它确实会生成一个“静态”网站,但同时也会提供一个 JavaScript 包(例如 Next 或 Gatsby)
  • 一个更专注于 HTML 的静态网站生成器,它有自己的模板/格式,而不是 JavaScript 组件(例如 Eleventy 或 Jekyll)

我知道有一些例外,但这涵盖了绝大多数网站生成器市场。

但我想两者兼得!

  • 我想用 JavaScript 组件来构建网站,因为它们周围的语法和工具比我们现在拥有的任何其他组件系统都要好。
  • 我希望静态输出实际上是零 JavaScript(除非我手动选择加入某些内容)。

这就是 Astro 所做的事情。

这些组件呢?

  • 它们可以是 .jsx 文件
  • 它们可以是 .svelte 文件
  • 它们可以是 .vue 文件
  • 这些是“渲染器”,并且您可以 自行携带(BYO)

Astro 也有自己的格式(.astro),它也很引人注目,因为

  • 它显然是 Astro 工作方式中的一等公民
  • 它非常类似于 JSX……
  • ……但更好,因为它会自动处理 <head> 的工作
  • 样式作用域开箱即用,通过普通的 <style> 标签
  • “围栏”内的 JavaScript 在构建期间运行。接下来我们看看这一点。

Astro 文件

我在上面提到了关于 .astro 语法的几个很酷的部分。在更高级别上,我只是喜欢它们的外观。如此少的样板文件!直接进入正题。

---
import SomeComponent from "../components/SomeComponent";

// This runs in Node, so you look at your command line to see it.
console.log("Hi.");

// Example: <SomeComponent greeting="(Optional) Hello" name="Required Name" />
const { greeting = 'Hello', name } = Astro.props;
const items = ["Dog", "Cat", "Platipus"];
---
<!-- JSX-like, but also more pleasantly HTML like, like this comment  -->
<div class="module">
  <h1>{greeting}, {name}!</h1>
  <ul>
    {items.map((item) => (
      <li>{item}</li>
    ))}
</ul>
</div>

<SomeComponent regular="props" />

<style>
   /* Scoped! */
  .module {
    padding: 1rem;
  }
</style>

顶部的“围栏”(---)是初始 JavaScript 代码所在的位置。如果该组件需要任何 prop,我会在这里提取 prop(如果喜欢,可以对其进行类型化),执行导入/导出,并为下面的模板设置数据。

感觉有点奇怪,但与 Astro 的风格一致,这本质上是 Node JavaScript。它在构建过程中运行。因此,我不会在浏览器控制台中看到 console.log() 语句,而是在命令行中看到它。

pages 样式路由

人们很容易说 Next.js 推广了这种方式,但实际上这个概念和文件系统一样古老。想想经典的 Apache 服务器是如何工作的。如果您有这样的文件系统

index.html
/about/
  index.html

在浏览器中,您可以访问 http://website.com/about,这将渲染 /about 文件夹下的 index.html 页面。这就是这里的路由方式。由于我拥有

/pages/
  index.astro
  about.astro

我将拥有一个主页以及一个 /about/ 页面。这是一种处理路由的非常简洁的方式——而不是需要自己构建路由,让组件独自处理。

如果要将网站的所有内容都保存在存储库中的 Markdown 文件中,这是首选方式。

我认为这对于博客和文档之类的内容非常普遍,尤其是因为它们已经是静态网站生成器的热门目标。而且在这些早期阶段,我认为我们会看到很多类似的 Astro 网站,人们会等待看看它是否准备好用于更大的项目。

一种使用 Markdown 的方法是直接在 Markdown 中创建页面。Markdown 也会有“围栏”(前置 matter),您可以在其中放入要使用的布局(最好使用 .astro 文件)并在需要时传入数据。然后 Markdown 文件的全部内容将流入 <slot />。非常棒

另一种令人非常满意的在 Astro 中使用 Markdown 的方法是使用内置的 <Markdown /> 组件。导入并使用它

---
import { Markdown } from 'astro/components';
---

<main>
  <Markdown>
    # Hello world!
    
    - Do thing
    - Another thing in my *cool list*
  </Markdown>

  <div>Outside Markdown</div>
</main>

您还可以从项目中的其他位置获取一些 Markdown,并将它们放入组件中。这会导致数据获取,所以接下来我们看看这一点。

数据获取规则

我们刚刚在谈论 Markdown,所以让我们在这里结束这个话题。您可以通过使用 fetchContent 在 Astro 内部“获取”数据。看看它有多简单

我获取了原始 Markdown,然后如果需要,可以使用它返回的 HTML,或者如果出于某种原因有意义,可以将其放入 <Markdown /> 组件中

---
import { Markdown } from 'astro/components';
const localData = Astro.fetchContent('../content/data.md');
---

<div class="module">
  <Markdown content={localData[0].astro.source} />
</div>

但我并不一定要只获取内部数据。我喜欢 Eleventy。在 Eleventy 构建期间,您当然可以从外部来源获取数据,但我认为它有点麻烦。您使用单独 JavaScript 文件中的代码获取数据,引入您自己的网络库,然后处理并将数据返回以在模板中的其他位置使用。就像这样。 在 Astro 中,数据获取可以在您需要它的组件旁边进行。

查看这个真实的示例,我从 CSS-Tricks 中获取数据并将其显示为卡片。

---
import Card from '../components/Card.astro';
import Header from '../components/Header';

const remoteData = await fetch('https://css-tricks.cn/wp-json/wp/v2/posts?per_page=12&_embed').then(response => response.json());
---

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>CSS-Trickzz</title>
    <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⭐️</text></svg>">
    <link rel="stylesheet" href="/style/global.css">

    <style lang="scss">
      .grid {
        margin: 4rem;
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        @media (max-width: 650px) {
          grid-template-columns: repeat(1, 1fr);
          margin: 2rem;
        }
        gap: 3rem;
      }
    </style>
</head>

<body>
  <main>
    <Header />

    <div class="grid">
      {remoteData.map((post) => {
        return(
          <Card 
            title={post.title.rendered}
            link={post.link}
            excerpt={post.excerpt.rendered}
            featured_img={post.featured_media_src_url}
          />
        )
      })}
    </div>

  </main>
</body>

</html>

我可以轻松地从 CSS-Tricks 数据构建一个页面

令人着迷的是数据发生在

  1. Node 中,而不是客户端,并且
  2. 在构建过程中。

因此,为了保持此类网站的更新,我必须定期运行构建/部署过程。

Astro 开箱即用地支持所有这些不同的框架,这有点奇怪。

我听到一些反对意见,认为 Astro 在 npm install 级别效率低下,因为您必须下载很多可能不需要或不使用的内容。我还听到一些人反对混合匹配 JavaScript 框架的想法。

我同意这感觉很奇怪,但我并不特别担心非用户界面方面的事情。当事情只发生在构建过程中,并且用户最终得到的只是 HTML 时,使用任何感觉良好的方法!如果您最终确实加载了基于组件的框架来执行页面交互操作,那么将其限制为一个框架肯定是有意义的。而且由于您在构建时获得了如此多的功能,因此也许使用专为 页面渲染后超轻量级交互 设计的内容是有意义的。

样式

假设您想使用 Sass 来为您的网站设置样式。许多网站生成器都会回避这个问题,将其作为一种理念。就像说“不,我们不想在这里表达意见,您想如何设置样式就如何设置”。我理解这一点,它可能是一个优势,因为有时过于武断的框架会让人们失去兴趣。但在我看来,这通常令人遗憾,因为我现在需要自己构建一些样式处理构建流程(例如 Gulp),而我真的很不想处理这些。

使用 Astro,其理念似乎是从一开始就支持各种流行的样式技术。

  • 只需 import "./style.css"; 使用普通样式表
  • .astro 文件中的任何位置使用 <style> 块,CSS 将作用于该组件…
  • …这类似于 CSS 模块,但只有在您使用 .jsx 文件时才需要,如果您使用,则支持。
  • .svelte.vue 文件的样式功能按预期工作。
  • Sass 内置其中,只需在任何位置的样式块上放置 <style lang="scss"> 即可。

样式文档 提供了更多详细信息。

花哨的可选 JavaScript 技巧

请允许我从自述文件中引用这段内容

  • <MyComponent /> 将呈现 MyComponent 的仅 HTML 版本(默认)
  • <MyComponent:load /> 将在页面加载时呈现 MyComponent
  • <MyComponent:idle /> 将使用 requestIdleCallback() 在主线程空闲时呈现 MyComponent
  • <MyComponent:visible /> 将使用 IntersectionObserver 在元素进入视口时呈现 MyComponent

这真是太棒了。默认情况下为 HTML,并且只有在您确实需要时才选择在客户端(JavaScript)运行组件,即使那样,也是在高效的条件下。

我将一个基于 Vue 的计数器(来自 他们的示例)放在我的演示站点上,并使用了 :visible 修饰符来查看它的工作原理。请查看

Vue 相关内容仅在需要时加载。就像 博文 中所说的那样

当然,有时客户端 JavaScript 是不可避免的。图像轮播、购物车和自动完成搜索栏只是少数几个需要一些 JavaScript 在浏览器中运行的示例。这就是 Astro 真正闪光的地方:当组件需要一些 JavaScript 时,Astro 只加载该组件(以及任何依赖项)。您网站的其余部分继续以静态的、轻量级的 HTML 形式存在。

Discord 非常活跃

我应该指出,Astro 非常非常新。在我写作的时候,他们甚至还没有真正的文档。使用一个文档仅以自述文件形式存在的框架可能感觉有点早。不过,他们正在努力!我看到了它的预览,因为我碰巧 在 Discord 中

我认为他们拥有一个公开的 Discord 非常明智,因为这意味着他们有一个快速反馈循环来改进框架。我发现加入其中非常有用。

我相信他们希望 Astro 发展成为远不止一个框架,而是一个完整的平台,其中 Astro 只是开源核心。您可以在 Learn with Jason 的一期节目 中听到 Fred 与 Jason 讨论此事。