Создание Endpoint в формате JSON для реализации поиска по сайту в Astro

Для реализации поиска по сайту, созданному на стеке Jamstack, можно воспользоваться популярной библиотекой List.js. У библиотеки неплохая документация на официальном сайте. Тем не менее, в зависимости от выбранной парадигмы, библиотеке может потребоваться доступ к структурированным данными постов сайта. В этой инструкции я покажу пример создания такого объекта при разработке сайта на Astro.

Для этого воспользуемся, встроенной в Astro, возможностью создания Endpoints любого формата. В папке pages создаём файл posts.json.js со следующим содержимым:

// src/pages/posts.json.js
import { getCollection } from "astro:content";
const posts = await getCollection("posts");

const json = posts.map((post) => ({
  date: post.data.date,
  title: post.data.title,
  description: post.data.description,
  body: post.body,
  url: `/posts/${post.slug}/`,
}));

export function GET() {
  return new Response(JSON.stringify(json));
}

Теперь, в процессе сборки сайта, дополнительно будет генерироваться Endpoint в формате JSON с данными из всех постов сайта, размещённых в формате Markdown.

При создании Endpoints в Astro расширение js отбрасывается, поэтому результирующий файл получит наименование posts.json и, на примере этого сайта, будет доступен по адресу https://geshov.ru/posts.json.

Полученный JSON с данными постов сайта можно использовать для реализации поиска по сайту при помощи библиотеки List.js:

# terminal
npm i list.js
<!-- src/pages/search.astro -->
<div id="posts">
  <input class="search" placeholder="Поиск" />
  <ul class="list"></ul>
</div>

<script>
  import List from "list.js";
  fetch("/posts.json")
    .then((response) => response.json())
    .then((json) => {
      const options = {
        valueNames: ["date", "title", "description", "body"],
        searchColumns: ["title", "description", "body"],
        item: (item) => `<li>
          <a href="${item.url}" class="title">${item.title}</a>
          <div class="date">${item.date}</div>
          <div class="description">${item.description}</div>
        </li>`,
        page: 10,
      };
      const list = new List("posts", options, json);
    });
</script>
AG & Dev © 2020 Moscow