使用 Hugo + Algolia 进行静态站点搜索 [译]

本文翻译自:Static site search with Hugo + Algolia 原作者:Chris Macrae

我们将介绍如何使用搜索服务提供商 Algolia 为你的 Hugo 网站设置快如闪电的搜索服务,Algolia 自称它们是 “建立搜索业务的最可靠平台”,我们将使用 Hugo 的自定义输出格式为我们的静态站点生成 JSON 搜索索引。然后我们将在 Algolia 上进行必要的配置,并使用 npmatomic-algolia 将新索引发送给 Algolia。最后使用 Serverless 简化更新搜索索引。

为什么选择 Algolia

有很多静态网站的搜索解决方案。您可以使用前端 Javascript 和 Lunr.jsFuse.js 等工具滚动自己的搜索,使用 ElasticSearchAmazon CloudSearch 建立强大的开源搜索技术,或者像 Algolia 这样的 SaaS 解决方案。所以问题是,是什么让 Algolia 如此出色?答案归结为两个因素:

  • JAMStack 的目标是消除服务器依赖性(也就是说不依赖服务器端代码)。所以我们为什么不使用 Algolia 的搜索 CDN.
  • Algolia 提供了非常慷慨的免费计划,其性能比 ElasticSearch 等开源解决方案快 200 倍。

扫盲:JAMstack 是指使用 JavaScript、API 和 Markup 构建的技术堆栈,JAM 是 JavaScript、API 和 Markup 的简称,前面第一个字母缩写,JAMstack 一种基于客户端 JavaScript,可重用 API 和预构建 Markup 的现代 Web 开发架构。

Algolia 如何工作

Algolia 提供 REST API 来查询和更新您的搜索索引。所有输入和输出都以 JSON 格式提供,使其在前端 Javascript 中非常容易使用。要创建,更新和维护 Algolia 搜索索引,您需要生成 Hugo 站点中所有内容的有效 JSON 数组。接下来我们一步步实现。

生成搜索索引

要开始使用 Algolia,您需要做的第一件事就是注册。一旦完成,您的下一步就是生成 JSON 搜索索引。使用 Hugo,我们将使用自定义输出格式功能执行此操作,该功能允许我们以不同的格式输出现有文档(在本例中为有效的 Algolia JSON 索引)。请打开 config.toml。在这里,我们将为您的自定义输出格式添加 Hugo 配置。

[outputFormats.Algolia]
baseName = "algolia"
isPlainText = true
mediaType = "application/json"
notAlternative = true

[params.algolia]
vars = ["title", "summary", "date", "publishdate", "expirydate", "permalink"]
params = ["categories", "tags"]

参数解释:

  • baseName 告诉输出格式如何查找此输出格式的 Hugo 布局
  • isPlainText 告诉输出格式使用 GoLan g的纯文本解析器进行布局,防止一些自动 HTML 格式化破坏你的 JSON
  • mediaType 告诉输出格式输出什么样的文件。
  • notAlternative循环遍历 .AlternativeOutputFormats 页面变量时告诉输出格式不被包含。
  • vars 设置要包含在索引中的页面变量。
  • params 设置要包含在索引中的自定义页面参数。

创建 JSON 模板

下一步是为 Hugo 提供自定义输出格式的 JSON 模板。为此,我们将创建一个新布局来执行此操作。将以下内容复制到 layouts/_default/list.algolia.json

{{/* Generates a valid Algolia search index */}}
{{- $.Scratch.Add "index" slice -}}
{{- $section := $.Site.GetPage "section" .Section }}
{{- range .Site.AllPages -}}
  {{- if or (and (.IsDescendant $section) (and (not .Draft) (not .Params.private))) $section.IsHome -}}
    {{- $.Scratch.Add "index" (dict "objectID" .UniqueID "date" .Date.UTC.Unix "description" .Description "dir" .Dir "expirydate" .ExpiryDate.UTC.Unix "fuzzywordcount" .FuzzyWordCount "keywords" .Keywords "kind" .Kind "lang" .Lang "lastmod" .Lastmod.UTC.Unix "permalink" .Permalink "publishdate" .PublishDate "readingtime" .ReadingTime "relpermalink" .RelPermalink "summary" .Summary "title" .Title "type" .Type "url" .URL "weight" .Weight "wordcount" .WordCount "section" .Section "tags" .Params.Tags "categories" .Params.Categories "authors" .Params.Authors)}}
  {{- end -}}
{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}

在此布局中,我们遍历所有当前页面的子项并执行以下操作:

  • 使用 .UniqueID 页面变量设置 Algolia 索引文档的 objectID 。
  • 循环文档的内置变量并将特定变量添加到文档中。
  • 循环文档的自定义 Front Matter 参数并将特定的参数添加到文档中。

输出指数

既然我们已经创建了自定义输出格式,它的布局,并配置了我们想要包含在索引中的变量和页面级参数,我们现在必须设置网站来实际创建 JSON 索引!

我们可以使用 outputs 参数以两种方式完成此操作:

  • 使用站点范围的 outputs 配置输出特定类型的所有内容的索引
  • 指定 outputs 每页打开,输出特定页面的索引。

出于本指南的目的,我们将做前者。再次打开配置文件,并添加以下内容:

[outputs]
home = ["HTML", "RSS", "Algolia"]

此配置告诉 Hugo 输出 HTML 文档,RSS Feed 和您网站主页的 Algolia 索引,该索引将包含您网站上的每个其他页面。

在您构建的站点中,您现在将找到一个 algolia.json 在根目录中调用的文件,我们可以使用它来更新 Algolia 中的索引。

在 Algolia 创建您的索引

转到您的 Algolia 应用程序仪表盘,然后单击 “新建应用程序”。

将应用程序设置为不容易忘记的名字(例如公司名称),然后选择社区作为您的计划。

然后,选择离您最近的地区。

您将被重定向到应用程序的仪表盘。选择左侧的 “索引” 选项卡,然后单击 “添加新索引”。给它一个唯一的名称(例如,您的网站的域名),因为这是我们在更新索引时会使用的。

最后,选择左侧的 API Keys 选项卡,然后复制 Application IDAdmin API Key,因为我们需要这些来更新索引。

将您的搜索索引发送给 Algolia

下一步是将您的搜索索引发送给 Algolia。对于本文,我们将使用一个伟大的NPM包来执行此操作:atomic-algolia。

atomic-algolia 是一个 NPM 包,可以对 Algolia 索引进行原子更新。这意味着它只更新已更改的记录,添加新记录或删除过期记录,并一次完成所有操作,以便您的索引永远不会与您网站的内容不同步。

这很重要,因为 Algolia 的计划基于索引上的操作,并对索引进行搜索,这个插件可确保您使用尽可能少的操作!我们的用户 @budparr 进行了快速测试,以了解使用原子 algolia 可以节省多少操作。结果令人印象深刻,你可以看到 hugo-algolia 产生了 4,613 次操作,而原子 - algolia 的 911 操作。

要开始使用,请确保已安装 Node。如果不这样做,可以通过下载适用于您的操作系统的安装程序来执行此操作。

更新您的索引

现在你有了一个 Algolia 索引,打开你的终端,导航到你的 Hugo 项目,并运行以下命令:

npm install atomic-algolia --save

这会将 atomic-algolia 软件包安装到本地 node_modules 文件夹,并使其可用于您的 Hugo 项目。

接下来,打开新创建的 package.json,我们将添加一个NPM脚本来更新索引。查找 “scripts” 并添加以下内容:

"algolia": "atomic-algolia"

现在,您可以通过运行以下命令来更新索引:

ALGOLIA_APP_ID={{ YOUR_APP_ID }} ALGOLIA_ADMIN_KEY={{ YOUR_ADMIN_KEY }} ALGOLIA_INDEX_NAME={{ YOUR_INDEX NAME }} ALGOLIA_INDEX_FILE={{ PATH/TO/algolia.json }} npm run algolia

使用 .env 文件

每次调用它时将环境变量传递给NPM脚本都不理想。这就是原子 algolia 支持 .env 文件的原因。在 Hugo 项目的根目录中创建一个名为的新文件 .env,并添加以下内容:

ALGOLIA_APP_ID={{ YOUR_APP_ID }}
ALGOLIA_ADMIN_KEY={{ YOUR_ADMIN_KEY }}
ALGOLIA_INDEX_NAME={{ YOUR_INDEX_NAME }}
ALGOLIA_INDEX_FILE={{ PATH/TO/algolia.json }}

现在,您可以通过运行更简单地更新索引:

npm run algolia

使用无服务器功能更新搜索索引

每次站点更改时都必须手动运行 NPM 脚本,尤其是在使用 Forestry.io CMS 等服务时。

这就是为什么我们创建了一个开源模板,用于创建无服务器 Webtask 功能,每次使用Web挂钩更新您的站点时,该功能都可以自动更新您的 Algolia 索引。

什么是 Serverless?

使用 Serverless,您可以设置在云中运行的功能,并且不需要运行 PHP,Node 等的完整后端服务器。这些功能非常适合执行更新 Algolia 索引等任务。无服务器基础架构是静态站点的完美组合。

配置

要开始,请运行以下命令将模板存储库克隆到本地计算机:

git clone https://github.com/forestryio-templates/serverless-atomic-algolia.git

然后,导航到模板目录并安装依赖项:

cd serverless-atomic-algolia
npm install serverless -g && npm install

接下来,如果您尚未设置 Webtasks 配置文件,则需要执行此操作。这可以直接从命令行完成。

serverless config credentials --provider webtasks

系统会要求您提供电话号码或电子邮件。您将立即收到验证码。输入验证码,您的个人资料将完全设置并可供使用。接下来,您需要使用索引和 Algolia 应用程序信息配置该功能。

首先,复制 config/secrets.yml.stubconfig/secrets.yml 然后在您喜欢的文本编辑器中打开它。

ALGOLIA_APP_ID: {{ YOUR_APP_ID }}
ALGOLIA_ADMIN_KEY: {{ YOUR_ADMIN_KEY }}
DEBOUNCE: 0

然后,config/index.js 在您喜欢的文本编辑器中打开:

module.exports = () => {
    var indexes = [
        {
            name: "YOUR_INDEX_NAME",
            url: "PUBLIC_URL_OF_INDEX"
        }
    ]
    return JSON.stringify(indexes)
}

更新 name 到您之前设置和索引的名字 url 来 yourdomain.com/algola.json,免去 yourdomain.com 您的网站的域名。

部署功能

现在我们可以通过运行来部署该功能:

serverless deploy

在终端中,您将收到部署成功的输出,包括新功能的公共URL。将其复制到剪贴板,因为这是我们在对站点进行更改时使用Web挂钩触发的URL。

设置 Webhook

最后,我们的最后一步是使用您的部署工具设置部署后 Web hook。每个工具的设置都会有所不同,但我们会为以下内容提供设置:

Forestry.io

转到 Forestry 中站点的“设置”页面,然后向下滚动到 Webhook URL 设置。

输入部署功能时收到的URL,然后单击“ 保存设置”。

现在 Forestry 每次完成部署您的网站时,都会调用您的函数来更新您的 Algolia 索引。

此设置仅在 Forestry 设置为处理站点的构建和部署时才有效。如果您使用第三方 CI 服务来构建您的站点(如GitLab CI或Netlify),则需要使用其 webhook 功能来触发您的功能。