如何为你的 Hugo 网站添加即时搜索功能

本文介绍了如何为 Hugo 网站添加即时搜索功能,并指明优化方向。

版权声明
本文为 Jimmy Song 原创。转载请注明来源: https://jimmysong.io/blog/hugo-instant-search-guide/
查看本文大纲

最近我用 Fuse 和 Hugo 导出的全站结构化数据(压缩后仅 2MB)做的即时搜索,还有快捷搜索地址 https://jimmysong.io/search/?q=关键词,定制了下结果展示页面,这就是开源的强大之处,任何地方都可以私人订制。

image
搜索结果展示页面

概览

下面我将分享下如何为你的 Hugo 网站添加即时搜索功能。大体步骤如下:

  1. 导出 Hugo 网站的结构化数据
  2. 使用 Fuse 库构建搜索的 JavaScript 代码
  3. 添加前端搜索模板
  4. 自动化更新网站结构化数据
  5. 进一步优化
提示

读者可以参考 hugo-blox-builder 这个项目中的搜索实现,下面是参考的代码:

1. 导出 Hugo 网站的结构化数据

首先,你需要为你的 Hugo 网站创建一个 JSON 文件,它将包含所有页面的必要元数据,如标题、描述、链接等。你可以通过 Hugo 的自定义输出格式来实现这一点。

在你的 Hugo 配置文件(通常是 config.tomlconfig.yaml)中,添加一个自定义输出格式:

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

[outputFormats.JSON]
mediaType = "application/json"
baseName = "index"
isPlainText = false

然后,在你的内容模板中(如 layouts/_default/list.json.json),定义输出的 JSON 结构:

{
  "data": [
    {{ range .Pages }}
    {
      "title": "{{ .Title }}",
      "url": "{{ .Permalink }}",
      "summary": "{{ .Summary }}"
    }
    {{ if not (eq .Next nil) }},{{ end }}
    {{ end }}
  ]
}

这将为你的整个站点生成一个 index.json 文件,其中包含所有页面的基本信息。当然你可能不想导出网站的所有页面,可以通过 Hugo 的语法,可定制化导出的 Section 或者不同类型页面。

2. 使用 Fuse 库构建搜索的 JavaScript 代码

接下来,使用 Fuse.js 库来实现前端的即时搜索功能。首先,你需要在你的网站中包含 Fuse.js 的库文件。你可以从 jsDelivr 等 CDN 加载它:

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

然后,在你的 JavaScript 文件中,加载并解析 index.json 文件,并使用 Fuse.js 进行搜索:

fetch('/index.json')
  .then(response => response.json())
  .then(data => {
    const fuse = new Fuse(data.data, {
      keys: ['title', 'summary'],
      includeScore: true
    });

    document.getElementById('search-input').addEventListener('input', function (e) {
      const results = fuse.search(e.target.value);
      displayResults(results);
    });
  });

function displayResults(results) {
  const searchResults = document.getElementById('search-results');
  searchResults.innerHTML = '';
  results.forEach(result => {
    const elem = document.createElement('div');
    elem.innerHTML = `<a href="${result.item.url}">${result.item.title}</a>`;
    searchResults.appendChild(elem);
  });
}

具体实现可以参考 wowchemy-search.js

3. 添加前端搜索模板

在你的网站中添加一个搜索框和结果显示区域:

<input type="text" id="search-input" placeholder="输入搜索词">
<div id="search-results"></div>

另外你还可以添加搜索快捷键,一般是组合键 ⌘/CTRL + K 来快速打开搜索页面。

具体实现可以参考 这个前端模板

4. 自动化更新网站结构化数据

为了保证搜索结果的实时性,可以通过 GitHub Actions 或其他 CI/CD 工具来自动化 Hugo 网站的构建和部署流程,确保 index.json 文件始终是最新的。

创建一个 .github/workflows/hugo_build.yml 文件,定义自动化流程:

name: Build and Deploy
on:
  push:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: Set up Hugo
      uses: peaceiris/actions-hugo@v2
      with:
        hugo-version: 'latest'
    - name: Build
      run: hugo --minify
    - name: Deploy
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./public

另外如果你的网站支持多语言,可以为每种语言分别生成 index.json 文件,并在不同的语言页面加载对应的索引文件。

5. 进一步优化

  • 缓存优化:为 index.json 设置合理的缓存策略,以减少服务器负载和提高响应速度。如果你是会用的是 Github Pages 作为静态网站,那么可以忽略这一步。
  • 数据压缩:压缩你的 index.json 文件,你可以选择导出网站的部分数据,比如某些 Section 的数据,对 Content 进行截取,或者压缩文件成 gz 格式,在 JavaScript 加载后再在前端解压,这样可以减少网络数据传输。
  • 搜索结果高亮:增加搜索结果中关键词的高亮显示,提升用户体验。
  • 高级搜索选项:允许用户通过特定字段(如作者、分类)进行过滤搜索。
  • 网络优化:异步加载用于搜索的 JavaScript 文件,

通过这些步骤,你可以有效地为你的 Hugo 网站添加一个高效且可定制的即时搜索功能。

总结

本文介绍了如何为 Hugo 网站添加即时搜索功能,并提供了进一步优化搜索功能的建议,包括缓存优化、搜索结果高亮显示和高级搜索选项。这不仅展示了开源技术的强大自定义能力,也使网站用户能更快更准确地找到所需信息。

最后更新于 2024/12/11