
Алексей Баранов
Добавляем поиск по тегам в статический блог на Next.js
Несмотря на то, что я немного сбавил обороты, количество постов в блоге понемногу прибавляется, а находить их становится сложнее, поэтому я решил добавить поиск постов по тегам.
Вот так он выглядит на момент написания этой статьи:
Результат
Процесс можно разделить на несколько этапов:
- Добавление тегов к статьям
- Генерация страниц для каждого тега
- Добавление ссылок на страницы
- Работа над поисковой выдачей
Добавление тегов к постам
Тут всё просто, как и в случае с рекомендациями, я решил захардкодить в frontmatter каждой статьи массив с тегами.
Например, для этой статьи массив выглядит следующим образом:
tags: ["улучшения блога", "nextjs"]
Если вы пойдёте этим же путём, то обратите внимание на то, что в названии тегов лучше не использовать кириллицу и спец. символы. О том как всё же использовать в тегах кириллицу читайте далее в статье.
Генерация страниц для каждого тега
Генерация страниц для тегов очень похожа на генерацию страниц постов.
Алгоритм очень простой и выглядит следующим образом:
Сбор уникальных тегов
О том как получить все посты и их метаданные я писал в статье о добавлении RSS фида.
Там же можно найти и полную реализацию метода getAllPosts.
А нам же остаётся только добавить все теги в массив и удалить оттуда дубли:
export function getAllTags(): string[] {
const notUniqueTags = getAllPosts().flatMap((p) =>
p.tags ? [...p.tags] : [],
);
return Array.from(new Set(notUniqueTags));
}
Генерация страниц
Для того чтобы сгенерировать страницы, нам нужен не только список тегов, но и список постов по тегу:
export function getAllPostsByTag(tag: string): Post[] {
return getAllPosts().filter((p) => p.tags?.includes(tag));
}
Далее добавляем компонент для отображения страницы:
type Params = {
params: {
tag: string;
};
};
// Компонент для отображения страницы
export default async function TagPage({ params }: Params) {
const decodedTag = getTagFromURI(params.tag);
const posts = getAllPostsByTag(decodedTag);
if (!posts.length) {
return notFound();
}
return (
<>
// Отображаем тут наши посты
</>
);
}
И генерируем статические страницы:
// Генерируем статические страницы в build-time
export async function generateStaticParams() {
const tags = getAllTags();
return tags.map((t) => ({
tag: getTagURI(t),
}));
}
Неочевидные моменты
Вы наверняка заметили что я использую функции getTagFromURI и getTagURI при работе с тегами.
Дело в том что на данный момент в Next.js существуют сложности с кириллическими путями.
export const getTagURI = (tag: string) => {
return process.env.NODE_ENV === "development" ? encodeURIComponent(tag) : tag;
};
export const getTagFromURI = (uri: string) => {
return decodeURIComponent(uri);
};
Добавление ссылок на страницы
Тут сказать особо нечего, единственный момент, который следует учитывать - не забывайте оборачивать теги в encodeURIComponent.
const TagLinks: React.FC = () => {
const tags = getAllTags();
return (
<div>
{tags.map((item, i) => (
<Link
href={`/tags/${getTagURI(item)}`}
key={i}
>
{`#${item}`}
</Link>
))}
</div>
);
};
Работа над поисковой выдачей
Для улучшения индексирования сгенерированные страницы можно добавить в файл sitemap сайта.
Для этого, в файл sitemap.ts, лежащий в корне сайта добавляем следующий код:
import { MetadataRoute } from "next";
import { getAllTags, getTagURI } from "@/lib/api";
export default function sitemap(): MetadataRoute.Sitemap {
const tags = getAllTags();
return [
// тут остальные страницы сайта
...tags.map((tag) => ({
url: `https://alexeybaranov.dev/tags/${getTagURI(tag)}`,
lastModified: new Date(),
priority: 0.7,
})),
];
}
На этом всё! 🎉
Подписывайтесь на мой Youtube канал, Telegram и на сообщество Вконтакте 🙂



