
Алексей Баранов
Добавляем RSS фид к статическому Next.js приложению
Сам я не пользуюсь RSS фидами, но так как формат ещё жив, решил добавить фид и для этого блога.
Процесс этот простой и проходит в 2 основных шага:
Генерация RSS фида
Для того чтобы сгенерировать фид, необходимо:
- получить список всех постов и их метаданные,
- сформировать RSS фид в формате .XML
- делать так при каждой сборке
Получение постов и их метаданных
Так как посты у меня хранятся в репозитории проекта в формате .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/blog/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://alexeybaranov.dev/feed.xml"
/>
</head>
Всё готово! 🎉
P.S.
Вот ссылка на мой RSS фид.
Также не забудьте подписаться на мой Youtube канал и Telegram 🙂



