Jamstack 网站的逻辑放在哪里?

Avatar of Max Kohler
Max Kohler

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

当我开始构建 Jamstack 网站时,我不得不弄清楚的一件事是,您的网站会经历不同的阶段,您可以在其中放置逻辑。

让我们来看一个特殊的例子,以便您了解我的意思。假设您正在为一个音乐场所制作一个网站。网站最重要的部分是活动列表,有些是过去的,有些是即将到来的。您需要确保将它们标记为这样,或者设计得非常清晰。这是基于日期的逻辑。您如何做到这一点?该逻辑在哪里存在?

对于 Jamstack,至少有四个地方需要考虑。

选项 1:自己将其写入 HTML

从字面上讲,坐下来编写一个 HTML 文件来表示所有事件。我们会查看事件的日期,确定它是过去还是未来,并为每种情况编写不同的内容。提交并部署该文件。

<h1>Upcoming Event: Bill's Banjo Night</h1>
<h1>Past Event: 70s Classics with Jill</h1>

这完全可以!但缺点是我们必须一直更新该 HTML 文件——一旦比尔的班卓琴之夜结束,我们就必须打开代码编辑器,将“即将到来”更改为“过去”,然后重新上传文件。

选项 2:编写结构化数据并在构建时执行逻辑

与其手动编写所有 HTML,不如创建一个 Markdown 文件来表示每个事件。日期和标题等重要信息以结构化数据的形式包含在其中。这只是一个选项。关键是我们可以直接访问此数据。它也可以是无头 CMS 或类似的东西。

然后,我们设置一个静态站点生成器,例如 Eleventy,它读取所有 Markdown 文件(或从您的 CMS 中提取信息)并将它们构建成 HTML 文件。最棒的是,我们可以在构建过程中运行我们想要的任何逻辑。执行复杂的数学运算、访问 API、运行拼写检查……一切皆有可能。

对于我们的音乐场所网站,我们可以将事件表示为如下所示的 Markdown 文件

---
title: Bill's Banjo Night
date: 2020-09-02
---

The event description goes here!

然后,我们通过编写如下所示的模板在构建过程中运行一些逻辑

{% if event.date > now %}
  <h1>Upcoming Event: {{event.title}}</h1>
{% else %}
  <h1>Past Event: {{event.title}}</h1>
{% endif %}

现在,每次构建过程运行时,它都会查看事件的日期,确定它是在过去还是将来,并根据该信息生成不同的 HTML。无需再手动更改 HTML 了!

这种方法的问题在于,日期比较只发生一次,在构建过程中。上面示例中的now变量将引用构建恰好运行的日期和时间。并且一旦我们上传了构建生成的 HTML 文件,这些文件就不会更改,直到我们再次运行构建。这意味着,一旦我们音乐场所的某个活动结束,我们就必须重新运行构建以确保网站反映这一点。

现在,我们可以自动化重建,使其每天发生一次,或者,甚至每小时发生一次。这实际上就是 CSS-Tricks 会议网站 通过 Zapier 做的事情。

会议网站每天使用 Zapier 自动化进行部署,该自动化会触发 Netlify 部署,确保信息是最新的。

但这可能会累积构建分钟数,如果您使用的是 Netlify 等服务,并且可能仍然存在某些边缘情况,用户会获得过时的网站版本。

选项 3:在边缘执行逻辑

边缘工作者是在每次收到请求时在 CDN 级别运行代码的一种方法。在撰写本文时,它们尚未得到广泛应用,但一旦它们可用,我们就可以这样编写日期比较代码

// THIS DOES NOT WORK
import eventsList from "./eventsList.json"
function onRequest(request) {
  const now = new Date();
  eventList.forEach(event => {
    if (event.date > now) {
      event.upcoming = true;
    }
  })
  const props = {
    events: events,
  }
  request.respondWith(200, render(props), {})
}

render()函数将获取我们处理过的事件列表并将其转换为 HTML,也许是将其注入预渲染的模板中。边缘工作者的最大优势在于它们速度极快,因此我们可以在服务器端运行此逻辑,同时仍然享受 CDN 的性能优势。

并且由于边缘工作者在每次有人请求网站时都会运行,因此我们可以确保他们会获得最新的版本。

选项 4:在运行时执行逻辑

最后,我们可以将结构化数据直接传递到前端,例如,以数据属性的形式。然后,我们编写 JavaScript 代码,在用户的设备上执行我们需要的任何逻辑,并动态操作 DOM。

对于我们的音乐场所网站,我们可能会编写如下所示的模板

<h1 data-date="{{event.date}}">{{event.title}}</h1>

然后,我们在页面加载后在 JavaScript 中进行日期比较

function processEvents(){
  const now = new Date()
  events.forEach(event => {
    const eventDate = new Date(event.getAttribute('data-date'))
    if (eventDate > now){
        event.classList.add('upcoming')
    } else {
        event.classList.add('past')
    }
  })
}

now变量反映用户设备上的时间,因此我们可以非常确定事件列表是最新的。因为我们是在用户的设备上运行此代码,所以我们甚至可以变得更花哨,例如根据用户的语言或时区调整日期的显示方式。

与生命周期中的前几个点不同,运行时持续时间与用户打开我们网站的时间一样长。因此,如果我们愿意,我们可以每隔几秒运行一次processEvents(),并且我们的列表将保持完美更新,而无需刷新页面。对于我们音乐场所的网站,这可能没有必要,但如果我们想在建筑物外的广告牌上显示这些事件,它可能派上用场。

您将把逻辑放在哪里?

虽然 Jamstack 的核心概念之一是我们在构建时尽可能多地工作并提供静态 HTML,但我们仍然可以决定将逻辑放在哪里。

您将把它放在哪里?

这实际上取决于您要做什么。您网站中几乎从未更改的部分完全可以在编辑时完成。当您发现自己一次又一次地更改某个信息时,可能是将其移动到 CMS 中并在构建时提取它的好时机。对时间敏感的功能(例如我们在此处使用的事件示例),或依赖于用户信息的功能,可能需要在生命周期的后期在边缘甚至在运行时发生。