作ったページのコンテンツに対して検索をかける機能がほしかったので、algoliaのフリープランを使って全文検索できるページを追加した

index 用の json を生成

参考サイトのとおりに作った

config.tomlに以下を追加


[outputFormats.Algolia]
  baseName = "algolia"
  isPlainText = true
  mediaType = "application/json"
  notAlternative = true
[params.algolia]
  vars = ["title", "summary", "content", "date", "publishdate", "description", "permalink", "keywords"]
  params = ["tags", "categories"]

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

# hugo v0.6以降はデフォルトでhtmlが表示されないためこちらの設定が必要
[markup.goldmark.renderer]
unsafe = true

出力する json のテンプレートは hugo のCustom Output Formatsを用いて行う

以下の設定を入れている

https://blog.piyo.tech/posts/2018-04-07-hugo-search-index/ より

本文を全部含めてしまうと Algolia の 1 データあたりのデータ上限を超えてしまうので、content は.Plain を 2000 文字で truncate するようにしました。また、サムネイルもを含めるようにしました

毎回全てのページを更新すると面倒なので、多分 30 日以内に作成した記事のみ json に出力している

後で作成する search ページを入れたくなかったので title が search のページを除外している

./src/layouts/_default/list.algolia.json

として以下を作成

{{/* Generates a valid Algolia search index */}}
{{- $.Scratch.Add "index" slice -}}
{{- $section := $.Site.GetPage "section" .Section }}
{{- range .Site.AllPages -}}
  {{- $delta := now.Sub .Date -}}
  {{- if or (and (.IsDescendant $section) (and (not .Draft) (not .Params.private))) $section.IsHome -}}
  {{- if (le $delta.Hours 720) -}}
  {{- if (and (eq .Kind "page") (ne .Title "search")) -}}
    {{- $.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 "content" (.Content | truncate 3000))}}
  {{- end -}}
  {{- end -}}
  {{- end -}}
{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}

これでhugo serverにてビルドしたときにpublic/algolia.jsonに index 登録用の json が出力される。

生成した json を index に登録

手動でやるならば、algolia のダッシュボードに行き、 該当する index にて、json ファイルをアップロードすれば良い

自動更新用に、node.js でレコード登録用スクリプト作成

しかし、更新したときに自動でalgolia.jsonを登録したい。このblogはnetlifyに自動デプロイ用のトリガーを設定しているため

ビルドに成功したら生成される json ファイルを登録するバッチ処理が走るように設定する

https://www.algolia.com/doc/api-reference/api-methods/add-objects/ を参考に作る

npm init

npm install --save algoliasearch
npm install --save dotenv

変数の管理は.envで行う

APP_ID=xxxx
API_KEY=xxxx
INDEX_NAME=xxxx
var algoliasearch = require("algoliasearch")
require("dotenv").config()

// apiKey need addObject acl
const appId = process.env.APP_ID
const apiKey = process.env.API_KEY
const indexName = process.env.INDEX_NAME

const records = require("../src/public/algolia.json")

var client = algoliasearch(appId, apiKey)
var index = client.initIndex(indexName)

var res = index.addObjects(records)

netlify.tomlを編集して hugo コマンドで build した後に node スクリプトを実行する

[build]
publish = "./src/public"
command = "hugo --gc --minify -s ./src --baseUrl='https://blog.uni-3.app' && cd ./algolia && npm install && node main.js""

のように&&でつなげるだけ

search 用ページ作成

参考ページの通りにやっている

instantsearch.jsを使う。cdnのコードを適当な html へコピペする

hugo コマンドでsearch.mdを作成。コンテンツ一覧に出さないよう、showPaginationfalseにしておく

---
title: "search"
date: 2019-01-02T18:49:06Z
showPagination: false
---

<div id="search-box">
</div>

<ul id="hits">
</ul>

<div id="pagination">
</div>

<script>
// instantSearchを初期化
var search = instantsearch({
  appId: 'X30EJUS2IA',
  apiKey: '791937af7891a84d16eae4f9176bb7aa',
  indexName: 'prod_blog',
  urlSync: false
});
search.addWidget(
  instantsearch.widgets.searchBox({
    container: '#search-box',
   placeholder: 'serch pages',
   poweredBy: true
  })
);
search.addWidget(
  instantsearch.widgets.hits({
    container: '#hits',
    templates: {
      empty: 'not found',
      item: '<li><code>{{ dateString }}</code> <a href="{{permalink}}">{{ title }}</a></li>'
    }
  })
);

search.addWidget(
  instantsearch.widgets.pagination({
    container: '#pagination',
    maxPages: 20,
    scrollTo: false
  })
);

search.start();

</script>

サイドバーから飛べるようにしたいのでconfig.tomlに以下を追加するこれは使用しているテーマにより設定方法が異なりそう。

[[menu.main]]
  weight = 1
  identifier = "search"
  name = "Search"
  pre = "<i class=\"sidebar-button-icon fa fa-lg fa-search\"></i>"
  url = "/search"

これでひとまず検索用のページも作られる

参考