Tìm kiếm với Algolia, Hugo và Vue.js

Trước đây, muốn tìm kiếm bài viết, tôi thường vào danh mục và tìm kiếm các tags như javascript, sass, css…Và với mong muốn tìm kiếm bài viết được tốt hơn nên tôi quyết định thử nghiệm với Algolia, kết hợp một xíu với Vue.js.

Tại sao là Algolia?

Thực ra đối với những người làm lập trình như tôi, thì lí do đầu tiên là được học thêm một công nghệ mới. Thứ hai là sau khi thử nghiệm Algolia, thời gian kết quả tìm kiếm mà Algolia trả về rất nhanh, làm tôi cũng rất bất ngờ và mong muốn tìm hiểu thêm về Algolia.

Bên cạnh đó, qua quá trình mới làm quen với Algolia tôi thấy nó có những điểm nổi bật sau:

  • Algolia cung cấp gói miễn phí cho bạn sử dụng
  • Giao diện quản lý dễ sử dụng cho phép bạn theo dõi, truy vết và giám sát các hoạt động tìm kiếm
  • Cung cấp các API Client cho nhiều ngôn ngữ như JavaScript, Node.js, Go, C#
  • Các thư viện Algolia cung cấp rất hay như Autocomplete, Algolia Places

Tạo JSON Search Index trong Hugo

Algolia cung cấp tìm kiếm theo chỉ mục với các định dạng file JSON, CSV hoặc TSV hoặc sử dụng API để thêm thông tin tìm kiếm được đánh chỉ mục.

Với Hugo mình sẽ giới thiệu các bạn cách tạo ra một file JSON và tải tập tin đó lên Algolia.

Đầu tiên, ta tạo một file json trong layouts/_default/ hoặc themes/[tên-theme-của-bạn]/layouts/_default/ với tên là list.algolia.json với cấu trúc như sau.

{{- $.Scratch.Add "index" slice -}}
{{- $section := $.Site.GetPage "post" .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 -}}

Tập tin JSON sẽ mang những thông tin được định nghĩa ở trên như authors, date, title

Tập tin sẽ được tạo ra từ những thông tin các bài viết chứa trong thư mục post. Bạn có thể thay post bằng thư mục bài viết của bạn trong thư mục content

Ở đây tôi sử dụng một số cú pháp về Functions trong Hugo. Bạn có thể tham khảo thêm nhé.

Tiếp theo ta mở tập tin config.toml và thêm một số cấu hình vào:

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

[params.algolia]
  vars = ["title", "description", "summary", "date", "lastmod", "permalink"]
  params = ["categories", "tags"]

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

Sau đó bạn chạy lệnh

$ hugo

Bạn sẽ có một tập tin là algolia.json trong thư mục public

Tải tập tin lên Alolia

Sau khi có tập tin algolia.jsonđăng ký xong một tài khoản Algolia. Bạn đăng nhập vào Algolia Dashboard.

  • Bạn tạo một App sử dụng Algolia. Ở đây tôi ví dụ app có tên là dangthanhblog

Tạo app sử dụng Algolia

  • Ở giao diện Dashboard bạn chọn Indices và nhấn vào Create index giả sử với tên là posts

Tạo index trong Algolia

Chọn **Manage index** -> **Upload file** chọn tập tin **algolia.json** trong thư mục **public** đã tạo được ở trên.
  • Ngoài cách tải trực tiếp tập tin lên, bạn có thể dùng atomic-algolia để tải tập tin lên Algolia thông qua NPM scripts hoặc serverless nhé.

    $ npm install atomic-algolia dotenv --save-dev

    Tạo một file .env với các thông số

    ALGOLIA_APP_ID=ALGOLIA_APP_ID
    ALGOLIA_ADMIN_KEY=YOUR_ALGOLIA_ADMIN_KEY
    ALGOLIA_INDEX_NAME=posts
    ALGOLIA_INDEX_FILE=algolia.json

    Ở đây tôi giả sử indexName tôi sử dụng là posts và tập tin có tên là algolia.json

    Sử dụng NPM scripts trong package.json

    "scripts": {
      "algolia": "atomic-algolia"
    }

    Chạy lệnh để tải file algolia.json lên Algolia

    $ npm run algolia

Tạo Algolia Component với Vue.js

Để hiển thị trên Hugo. tôi tạo ra một trang static templates với tên gọi là archives.md trong thư mục content như sau:

---
type: "static"
layout: "archives"
---

Sau đó tạo thêm file HTML có tên là layouts/static/archives.html tương ứng với layout được khai báo ở trên.

Algolia cung cấp một thư viện JavaScript để bạn dễ dàng kết với Algolia thông qua Instantsearch.js hoặc Vue Instantsearch.

Vì tôi đã giới thiệu Vue.js có một tính năng rất hay đó là Component. Nên tôi quyết định viết Component này sử dụng Vue InstantSearch vừa giúp bạn biết thêm về cách xây dựng Component trong Vue thông qua thuộc tính props.

Vue.component('SearchAlgoliaComponent', {
  name: 'SearchAlgoliaComponent',
  template: `
    <ais-index
      :app-id="appId"
      :api-key="apiKey"
      :index-name="indexName"
      :routing="true">
      <ais-search-box placeholder="Tìm kiếm tiêu đề hoặc nội dung bài viết..."></ais-search-box>
      <ais-highlight :hit="hit" attribute="title"></ais-highlight>
      <ais-results>
        // Your display results
      </ais-results>
    </ais-index>
  `,
  props: {
    appId: {
      type: String,
      require: true
    },
    apiKey: {
      type: String,
      required: true
    },
    indexName: {
      type: String,
      required: true
    },
    routing: {
      type: Boolean,
      default: true
    }
  }
});

Vậy là ta đã có một Component sử dụng Vue cho Algolia. Giờ ta sẽ sử dụng nó trong layouts/static/archives.html nhé.

<main id="app">
  <search-algolia-component 
    :appId="yourAppId" 
    :apiKey="yourApiKey" 
    :indexName="yourIndexName"/>
</main>

appIdapiKey bạn vào trong Dashboard của Algolia và chọn API keys để lấy thông tin nhé.

Giờ ta đã có một trang tìm kiếm sử dụng Algolia, Hugo và Vue.js. Bạn có thể trải nghiệm hoặc có thể chỉnh sửa thêm cho SearchAlgoliaComponent theo cách bạn muốn hiển thị nhé.

Đặng Văn Thanh
Có đam mê về lập trình và các vấn đề về phát triển web.