The Issue of the Day Before

為 hugo 產生的網站增加搜尋功能

hugo -

Why

日記寫多了,就需要做索引卡片,才容易找。

What

fusejs

fusejs 輕量級零依賴的模糊搜索函式庫。

hugo

hugogolang 寫的靜態網站產生器。

How

在使用 fusejs 之前你必須為你要搜尋的網站建立一個 json 格式的索引檔。

例如,一個包含標題,作者和網址的物件陣列。

list.json
[
  {
    "title": "Crossorigin Anonymous",
    "content": "......"
    "link": "https://hokang.info/crossorigin-anonymous/"
  },...
]

然後將該內容傳入建立一個 Fuse 物件後,便利用他來搜尋。

const options = {
  // isCaseSensitive: false,
  // includeScore: false,
  // shouldSort: true,
  // includeMatches: false,
  // findAllMatches: false,
  // minMatchCharLength: 1,
  // location: 0,
  // threshold: 0.6,
  // distance: 100,
  // useExtendedSearch: false,
  // ignoreLocation: false,
  // ignoreFieldNorm: false,
  // fieldNormWeight: 1,
  keys: [
    "title",
    "content"
  ]
};

const fuse = new Fuse(list, options);

const search = (pattern) => fuse.search(pattern)

如上,

現在只要將要搜尋的字串傳給 function search 便可得回一個依文字距離大小排列的搜尋結果。

例如,

[
  {
    "item": {
      "title": "Crossorigin Anonymous",
      "content": "......"
      "link": "https://hokang.info/crossorigin-anonymous/"
    },
    "refIndex": 0
  },...
]

所以,如何為網站產生一個索引檔是最關鍵的,而這正好可以利用 Hugojsonify 來產生。 編寫一個為每一頁產生一個物件的模板。 例如,

layouts/_default/index.json
{{- $.Scratch.Add "index" slice -}}
{{- range .Site.RegularPages -}}

    {{- $.Scratch.Add "index" (dict dict "title" .Title "content" .Plain "link" .Permalink) -}}

{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}

在設定檔上增加 JSON 格式。

config.toml
[outputs]
  home = ["HTML", "RSS", "JSON"]

如此,在每次產生網頁時便會在 public 目錄下產生一個 index.json 檔。

接下來,可為需要查詢功能的網頁增加 javascript

<script src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2/dist/fuse.min.js">

const search = (pattern) => fetch('/index.json')
  .then(response => response.ok ? response.json() : [])
  .then(data => new Fuse(data, options))
  .then(fuse => fuse.search(pattern))

// 將輸入的查詢字串傳入搜尋函式
search(document.getElementById('#searchInput').value)

上述為極簡的處理,可以改進的地方很多。 有興趣的可以進一步參考 hugo fastsearch

閱讀在雲端