JAMstack 网站通常被认为是静态的。对它们更准确的理解是,它们是可以以静态方式托管的网站。这种差异可能看起来只是语义上的,但由于许多简化构建运行和部署到静态托管基础设施的工具和服务的兴起,此类网站可能比你想象的要更新鲜和更具动态性,同时仍然能够从静态托管基础设施中提供服务,并带来所有好处。
一个经常被用作网站无法静态托管的示例的功能是评论。评论引擎需要处理提交、允许审核,并且本质上是“动态”的。

由于可用于 JAMstack 网站的工具生态系统不断发展,因此有了解决方案。让我们来看一个你可以在自己的网站上使用的示例,该示例
- 不依赖于客户端 JavaScript
- 可以与任何静态站点生成器配合使用
- 包含审核功能
- 在需要审核新评论时发送通知
- 将评论烘焙到你的网站中,以便它们快速加载并在搜索中显示
此示例利用了Netlify的一些功能,Netlify 是一个用于自动化、部署和托管 Web 项目的平台,但许多原则可以与其他平台一起使用。

存储我们的内容
我们将创建 2 个表单,以在评论从评论者到内容的不同阶段接收所有评论。当 Netlify 看到一个<form>
时,它会为表单收集的数据创建一个唯一的数据存储。我们将充分利用这一点。
- 表单 1) 一个队列,用于保存所有新的评论提交。换句话说,一个存储所有等待审核的评论的存储。
- 表单 2) 包含所有已批准的评论。
审核的行为将是某人查看每个新提交并决定,“是的!”或“不!”。那些被否定的将从队列中删除。那些被批准的将被发布到已批准的评论表单中。

由于Netlify 提供对我们表单中提交内容的 API 访问,因此已批准评论表单中的所有评论在后续的站点构建中被我们的静态站点生成器使用。

评论表单
每个页面都包含一个 HTML <form>
。通过向网站中的任何 HTML 表单元素添加netlify
的布尔属性,Netlify 将自动为你生成表单的 API,并为你收集所有提交到该表单的内容。稍后你还可以通过该 API 访问提交内容。方便!
每个页面上的评论<form>
看起来非常像这样(为清晰起见,省略了一些类和额外的副本)
<form netlify name="comments-queue" action="/thanks">
<input name="path" type="hidden" value="{{ page.url }}">
<p>
<label for="name">Your name</label>
<input type="text" name="name" id="name">
</p>
<p>
<label for="email">Your email</label>
<input type="email" name="email" id="email">
</p>
<p>
<label for="comment">Your comment</label>
<textarea name="comment" id="comment"></textarea>
</p>
<p>
<button type="submit">Post your comment</button>
</p>
</form>
你可能会注意到,表单还包含一个type="hidden"
字段,让我们知道此评论属于网站上的哪个页面。我们的静态站点生成器在生成站点时为我们填充了该字段,并且稍后在决定哪些评论应显示在哪个页面上时将使用它。

提交和通知
当通过评论表单发布新评论时,Netlify 不仅会为我们存储该评论,还可以发送通知。这可能是
- 电子邮件
- Slack 通知
- 我们选择的 Webhook。
这些使我们有机会稍微自动化一些事情。
新提交会导致通知发布到 Slack。我们将在 Slack 客户端中查看提交的内容以及提交到哪个页面。

为了使事情更加流畅,我们可以稍微修改一下通知,使其包含一些操作按钮。一个按钮删除评论,一个按钮批准评论。在乘坐公交车时,从手机上的 Slack 通知中批准新评论感觉很棒。

如果没有运行一些逻辑,我们就无法使这些按钮工作,我们可以在 Lambda 函数中执行此操作。Netlify 最近也添加了对 Lambda 函数的支持,使编写和部署 Lambda 成为部署过程的一部分。你无需在 Amazon 的 AWS 配置设置中四处搜索。
我们将使用一个 Lambda 函数来向我们的 Slack 通知添加一些按钮,以及另一个 Lambda 函数来处理单击任意一个按钮的操作。
将评论添加到网站中
在将新批准的评论发布到我们已批准的评论表单后,我们又回到了使用 Netlify 提供的提交事件触发器。每次将内容发布到已批准的评论表单时,我们都希望将其包含在网站中,因此我们让 Netlify 自动重建和部署我们的网站。

大多数静态站点生成器都有一些数据文件概念。Jekyll 使用[_data]
目录中的文件,Hugo 有类似的数据目录。此示例使用Eleventy作为其静态站点生成器,它具有类似的概念。我们将利用这一点。
每次我们运行站点构建时,无论是在本地开发环境中还是在 Netlify 中通过其自动化构建,第一步都是将所有外部数据提取到本地数据文件中,然后我们的SSG可以使用这些文件。我们使用Gulp 任务来执行此操作。
借助从对 Netlify 的表单提交 API 的调用中填充的`comments.json`文件,该 API 获取了我们所有已批准的评论,我们的SSG现在可以像往常一样构建网站并将正确的评论烘焙到我们页面的 HTML 中。

一些好处
这很有趣,但为什么要费心呢?
是的,你可以使用 Disqus 等工具通过几行 JavaScript 将评论添加到静态托管的网站中。但这会添加一个外部 JavaScript 依赖项,并导致有关你内容的评论远离内容本身。并且只有在 JavaScript 加载、提取数据并将其注入到你的网站中后,它才可用。
而此方法导致评论直接烘焙到网站内容中。它们将在 Google 搜索中显示,并且将在无需任何客户端 JavaScript 的情况下作为网站的一部分加载。
更好的是,你可以将它们与你的其他内容一起直接提交到你的代码存储库中,这将为你带来更多安心和未来的可移植性。
示例站点和所有代码都可供探索。如果你愿意,可以尝试提交评论(尽管可怜的Phil需要在这些评论出现在示例站点上之前审核任何评论,但这只会让他感到被爱)。
更好的是,你可以克隆此示例并只需点击几下即可将自己的版本部署到 Netlify。示例站点说明了如何操作。
现在就让我看看幕后情况!
如果你想查看使用此系统管理网站的管理员的行为方式,而无需自己获取副本,则此简短视频将逐步介绍评论的制作、审核和合并到网站中的过程。
这是一个有趣的想法,但是每次批准新评论后都重建网站或页面似乎有点蠢,特别是如果网站很大或变得很大。可能最好是每天运行一个 Web 作业来执行此操作 - 但即使每天重建一次网站也似乎很愚蠢。
我个人认为内容不会经常改变非常适合 Jamstack。虽然评论也可以实现,但这有点过分了。评论是动态的,因此第三方插件或 RESTful API 解决方案看起来更加成熟。换句话说,Jamstack 可以混合使用,以提供最符合需求的结果!
感谢 Nick,
我同意你的观点,如果你的网站页面数量很多,评论频率也很高,你可能希望避免为每个已批准的评论重新生成网站。在这种情况下,没有理由不能调整此机制以减少重新生成和重新发布的频率。
我认为,原则和机制可以保持不变,而不会遇到你提到的问题。
但是,我不同意评论是动态的并且属于第三方系统。这条评论和你自己的评论都与这篇文章相关,最好将其作为本出版物内容的一部分保留。依赖远程第三方不如将有关你内容的评论保留在你内容中那样理想。
如果我们可以在页面的 HTML 中提供评论,而不是等待第三方 JavaScript 加载、获取内容(以及他们可能想要插入的任何广告),然后在页面中呈现其余内容,则渲染性能、可靠性、持久性和可发现性都会得到提高。
当评论中的内容出现在搜索结果中并以这种方式将人们带到你的内容时,这也很不错。
此示例探讨了当生成和部署网站的成本(在时间、金钱和精力方面)接近于零时可能发生的情况。这种情况已经成为现实。
嗨,我是 Netlify 技术栈和易于部署系统的忠实粉丝。但是,对于这个评论系统来说,在繁忙的网站上批准每个评论会不会很麻烦?你如何建议在没有手动批准的情况下实现评论系统,同时还能有效地过滤恶意评论/垃圾邮件?
感谢 Kevin!
我认为这是一个合理的担忧。任何需要审核所有提交内容的评论系统都会有一些开销。我尝试通过这个示例说明的是,使用以下构建块
静态生成的网站
基于钩子触发的自动化脚本构建
来自表单提交事件的可配置通知
为您处理表单提交的表单 API
编写和触发无服务器函数的能力
… 你可以使用相当强大的功能,并且可以使用这些工具创建各种东西。这不是一个产品,而是一个思考的起点。
对于我们中的许多人,包括那些运营自己个人博客的人,我认为如果以方便的方式交付,每个提交的通知都没问题。无论如何,我们现在使用的任何工具都可能会收到此通知。但是对于评论量更大的大型网站,你是对的,也许审核控制台会更好。
此模型完全支持添加一个简单的审核控制台。我们已经可以通过 API 访问等待审核的评论队列,并且可以使无服务器函数执行我们需要的任何操作。一个显示所有等待审核的评论以及能够批量批准/删除它们的页面将是对此的简单扩展。
也许我会扩展示例以包含它。
我很好奇,其他人如何扩展此示例的功能?
我觉得如果你想的话,你可以发布所有出现的评论,并使用其他审核技术。
对于垃圾邮件,你可以使用验证码技术或在评论表单中使用 Netlify 的垃圾邮件防护。对于恶意评论,你也可以在事后通过将其从数据集中删除并触发构建来进行审核。
嗨,Kevin。你可以使用 Lambda 函数执行你想要实现的任何过滤,然后将通过自动化过滤的评论推送到“已批准”队列中。这将是一个几乎相同的架构,尽管你只需要一个 Lambda 而不是两个。
@philhawksworth
嗨,感谢你的解释!这完全说得通。我认为管理一批回复非常棒!我明白你的意思,这篇文章是一个思考的起点。它非常可扩展,我现在更多地了解了可能性!
@bryan 和 @matt
这些都是很棒的想法!我一定会尝试实现这些过滤 Lambda 函数,然后将它们发送到队列中!我可以看出如何使用钩子来实现有效的过滤。
谢谢大家!
我认为这不是问题。除非你在树莓派上部署构建,否则每次重建最多只需要几秒钟。我有一个由 Hugo 提供支持的静态网站,大约有 200 篇帖子、100 个标签和几个类别,它需要不到 5 秒的时间来构建并将所有内容上传到我的 Web 服务器。
在 Jekyll 中,这可能是一个问题,在 Jekyll 中,网站构建在任何包含多个帖子、包含文件或分页页面的网站上可能需要几分钟。
话虽如此,我们的工作站点托管在 Netlify 上,每天重建 20 次左右。这似乎没有造成问题,尽管我不知道如果收到数十条评论是否会发生这种情况。
就评论发表到发布之间的时间而言,由于人为干预,我期望在其他系统中需要合理的时间进行审核,对此我感到满意。
如果问题更多的是在 Netlify 上等待许多长时间构建,只要单个构建不超过 30 分钟(超时前的最大允许时间),这都不是问题。
如果你向 Netlify 发送许多构建请求,构建机器人足够智能,可以忽略当前正在运行的构建之后排队的任何请求,除了最近排队的构建。因此,在当前构建运行之后,它将跳过所有其他构建并运行最终构建。
这仅仅是将所有部署视为独立且不可变的另一个优势。
@bryan,@matt
是的,你确实可以使用 Netlify 的蜜罐过滤和验证码支持的组合。两者都有助于减少垃圾邮件到达 Lambda 之前。为了简化起见,我在此示例中省略了这些内容,此示例已经介绍了许多其他机制。
我个人希望在审核流程中的某个地方进行一定程度的人工干预,但同意尽可能实现自动化。