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

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

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

Так как формат 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://baranov.guru";

  const feedOptions = {
    language: "ru",
    title: "Baranov.Guru | RSS feed",
    description:
      "Личный блог. Пишу о разработке софта, предпринимательстве и просто об интересных мне вещах",
    id: site_url,
    link: site_url,
    image: `${site_url}/assets/authors/avatar.webp`,
    favicon: `${site_url}/favicon/favicon.ico`,
    copyright: `All rights reserved ${new Date().getFullYear()}, Baranov.Guru`,
    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> элементе вашей страницы появится следующая строчка:

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

Всё готово! 🎉

P.S.

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

Расскажите о вашем проекте

Связаться иначе

Часто задаваемые вопросы

Фид даёт подписчикам и сервисам (читалки, агрегаторы, импорт в соцсети) единый XML со свежими постами без парсинга HTML. Формат по-прежнему востребован для блогов и новостных лент — см. наш фид в конце статьи.

Фид собирается после успешного next build: скрипт в postbuild читает посты из репозитория и пишет XML в папку out вместе с остальной статикой. При каждом деплое лента обновляется автоматически.

Посты в .md в каталоге _posts: обход файлов, разбор frontmatter через gray-matter, сортировка по date — как в разделе получение постов. Тот же getAllPosts удобно переиспользовать для sitemap.

Библиотека feed: задаёте заголовок, описание, язык и для каждого поста title, link, description, date — затем feed.rss2() и запись в файл. Подробности — в разделе формирование XML.

В примере из статьи — ./out/feed.xml (каталог результата статической сборки). URL в проде должен совпадать с тем, что указан в metadata.alternates и в feedLinks фида.

В Root Layout добавьте metadata.alternates.types с типом application/rss+xml — на страницах появится link rel="alternate" в head. Раздел добавление на страницы.

RSS — для людей и подписок (полные записи в ленте). Sitemap — карта URL для поисковиков (статья). Яндекс.Турбо и импорт ВКонтакте — отдельные форматы и сценарии (Турбо, VK).

Вам может быть интересно

Добавляем Яндекс Турбо-страницы к блогу на Next.js
Добавляем Яндекс Турбо-страницы к блогу на Next.js

Добавляем Яндекс Турбо-страницы к блогу на Next.js

5 мин.

Для того чтобы красиво отображаться в поисковой выдаче Яндекса решили добавить Яндекс Турбо-страницы к блогу...

Пост#nextjs#yandex
Автопостинг в VK через RSS feed
Автопостинг в VK через RSS feed

Автопостинг в VK через RSS feed

4 мин.

Заметили в настройках сообщества в VK интересную настройку, связанную с фидами. И понеслось...

Пост#соцсети#фиды
Добавляем sitemap.xml в Next.js приложение
Добавляем sitemap.xml в Next.js приложение

Добавляем sitemap.xml в Next.js приложение

9 мин.

Инструкция по добавлению sitemap.xml в Next.js приложение...

Пост#nextjs#seo
Добавляем поиск по тегам в статический блог на Next.js
Добавляем поиск по тегам в статический блог на Next.js

Добавляем поиск по тегам в статический блог на Next.js

5 мин.

Инструкция по добавлению простейшего поиска по тегам в статическом Next.js блоге...

Пост#туториалы#nextjs
Добавляем поддержку MDX в Next.js приложение
Добавляем поддержку MDX в Next.js приложение

Добавляем поддержку MDX в Next.js приложение

3 мин.

Инструкция по добавлению поддержки MDX в Next.js приложение...

Пост#nextjs
Хостинг в S3 от Яндекса
Хостинг в S3 от Яндекса

Хостинг в S3 от Яндекса

6 мин.

Рассказываем как использовать Yandex Object Storage для хостинга статического сайта...

Пост#yandex
Добавляем robots.txt в Next.js приложение
Добавляем robots.txt в Next.js приложение

Добавляем robots.txt в Next.js приложение

5 мин.

Инструкция по добавлению robots.txt в Next.js приложение...

Пост#nextjs#seo
Добавляем рекомендации постов и блок "Поделиться в соц. сетях"
Добавляем рекомендации постов и блок "Поделиться в соц. сетях"

Добавляем рекомендации постов и блок "Поделиться в соц. сетях"

4 мин.

Изучали различные блоги, аналогичные нашему и решили добавить блок "Поделиться в соц. сетях", а так же простейший механизм рекомендаций статей. Вот что из этого вышло...

Пост#туториалы
Подключение счётчика Яндекс Метрики к Next.js приложению
Подключение счётчика Яндекс Метрики к Next.js приложению

Подключение счётчика Яндекс Метрики к Next.js приложению

13 мин.

Инструкция по добавлению счётчика Яндекс Метрики к Next.js блогу...

Пост#nextjs#yandex