Алексей Баранов

Добавляем RSS-фид к статическому Next.js приложению

Cover Image for Добавляем RSS-фид к статическому Next.js приложению
Алексей Баранов
Алексей Баранов

Добавляем RSS фид к статическому Next.js приложению

Сам я не пользуюсь RSS фидами, но так как формат ещё жив, решил добавить фид и для этого блога.

Процесс этот простой и проходит в 2 основных шага:

Генерация RSS фида

Для того чтобы сгенерировать фид, необходимо:

Получение постов и их метаданных

Так как посты у меня хранятся в репозитории проекта в формате .md, то для получения всех постов мне просто необходимо:

  • получить список файлов в директории с постами,
  • пройти по каждому посту и получить метаданные

Для получения метаданных я воспользовался пакетом gray-matter

npm i gray-matter

В результате получился такой код:

import fs from "fs";
import { join } from "path";

import matter from "gray-matter";

import { Post } from "@/interfaces/post";

const postsDirectory = join(process.cwd(), "_posts");

export function getPostBySlug(slug: string) {
  const realSlug = slug.replace(/\.md$/, "");
  const fullPath = join(postsDirectory, `${realSlug}.md`);
  const fileContents = fs.readFileSync(fullPath, "utf8");
  const { data, content } = matter(fileContents);

  return { ...data, slug: realSlug, content } as Post;
}

export function getAllPosts(): Post[] {
  const slugs = fs.readdirSync(postsDirectory);
  const posts = slugs
    .map((slug) => getPostBySlug(slug))
    // сортируем посты по дате в порядке убывания
    .sort((a, b) => (a.date > b.date ? -1 : 1));
  return posts;
}

Формирование .XML фида

Для того чтобы добавить RSS фид я воспользовался пакетом feed.

Устанавливаем его командой:

npm i feed

Алгоритм следующий:

  • сформировать описание фида,
  • пройти по списку постов, и сформировать feedItem для каждого поста,
  • записать всё в .xml файл

У меня получился вот такой скрипт:

import fs from "fs";

import { Feed } from "feed";
import path from "node:path";

import { getAllPosts } from "../api";

export default async function generateRssFeed() {
  console.log("Generating RSS feed...");

  const allPosts = await getAllPosts();
  console.log(`Found ${allPosts.length} posts.`);

  const site_url = "https://alexeybaranov.dev";

  const feedOptions = {
    language: "ru",
    title: "Алексей Баранов. Блог | RSS feed",
    description:
      "Личный блог. Пишу о разработке софта, предпринимательстве и просто об интересных мне вещах",
    id: site_url,
    link: site_url,
    image: `${site_url}/assets/blog/authors/avatar.png`,
    favicon: `${site_url}/favicon/favicon.ico`,
    copyright: `All rights reserved ${new Date().getFullYear()}, Alexey Baranov`,
    generator: "Feed for Node.js",
    feedLinks: {
      rss2: `${site_url}/rss.xml`,
    },
  };

  const feed = new Feed(feedOptions);

  allPosts.forEach((post) => {
    console.log(`Adding rss item for post ${post.slug}`);
    feed.addItem({
      title: post.title,
      id: `${site_url}/posts/${post.slug}`,
      link: `${site_url}/posts/${post.slug}`,
      image: `${site_url}${post.coverImage}`,
      author: [{ name: post.author.name }],
      description: post.description,
      date: new Date(post.date),
    });
  });

  const feedPath = path.resolve("./out/feed.xml");

  fs.writeFileSync(feedPath, feed.rss2());

  console.log(`Rss feed is written to ${feedPath}.`);
}

Автоматизация сборки фида

Добавляем в package.json скрипт postbuild.

{
  "scripts": {
    "build": "next build",
    "postbuild": "npx tsx ./src/lib/feeds/generate.ts"
  }
}

Он запустится сразу же после успешной сборки проекта и запишет фид в папку с результатами сборки.

Добавление информации о фиде на страницы сайта

Теперь осталось только добавить информацию о фиде на страницы сайта, для того чтобы различные расширения и боты могли легко найти его и отобразить для пользователей.

В файл с Root Layout нашего приложения добавляем следующий код:

export const metadata: Metadata = {
  alternates: {
    types: {
      "application/rss+xml": "/feed.xml",
    },
  },
};

Если вы всё сделали правильно, то в элементе вашей страницы появится следующая строчка:

<head>
  <link
    rel="alternate"
    type="application/rss+xml"
    href="https://alexeybaranov.dev/feed.xml"
  />
</head>

Всё готово! 🎉

P.S.

Вот ссылка на мой RSS фид.

Также не забудьте подписаться на мой Youtube канал и Telegram 🙂