en
Как создать RSS канал в Nuxt 3

Как создать RSS канал в Nuxt 3

Что такое RSS

Это файл в формате XML, который используется на сайтах для получения информации об обновлениях страниц и выходе новых статей. Формат читается в браузерах, а также в специальных нативных или онлайновых RSS читалках.

Я на всех своих сайтах подключаю RSS ленты и, несмотря на некий спад популярности этого формата, знаю многих людей, которые до сих пор им пользуется. Я тоже в их числе.

Подключаем RSS к Nuxt

Как всегда, хотелось магии, чтобы просто подключить и забыть, но в своих поисках не нашёл готовой рабочей библиотеки для Nuxt, поэтому решил использовать библиотеку node-rss.

Из плюсов такого решения — можно легко настроить RSS под свои задачи. К примеру, добавить вторую ленту для альтернативного языка, или отфильтровать те страницы, которые в ленте не нужны.

Устанавливаем node-rss.

npm i -D rss

И если в проекте используется TypeScript, как в моём случае, устанавливаем типы к нему.

npm i -D @types/rss

Конфигурация Nuxt

Для RSS ленты нам потребуется пререндер страницы. Поэтому в файле nuxt.config.ts, в секции Nitro, прописываем маршрут для каждой ленты RSS на сайте.

export default defineNuxtConfig({
  nitro: {
    prerender: {
      routes: ['/rss.xml'],
    },
  },
})

Создание статьи

Для того чтобы передавать информацию об обновлениях страниц в правильном формате, нам потребуется включить в текст каждой страницы метаданные в формате YAML, так называемый frontmatter. К примеру файл статьи /content/posts/1.my-article.md может содержать следующие поля:

---
title: Заголовок статьи
description: подзаголовок статьи
createdAt: 2023-09-01
---

Конечно, frontmatter может содержать и другие данные, например, имя файла картинки, тема статьи, время прочтения и т.д., но именно поля заголовка, описания и дата создания необходимы для формирования валидной структуры ленты RSS.

Создание маршрута

Теперь создаём серверный маршрут для RSS ленты. Допустим URL для неё будет https://sitename.com/rss.xml.

Добавляем в файл server/routes/rss.xml.ts следующий код:

import { serverQueryContent } from '#content/server'
import RSS from 'rss'

interface RSSItem {
  title: string
  description: string
  createdAt: string
  _path: string
}

const hostname: string = 'sitename.com'

export default defineEventHandler(async (event) => {
  const feed = new RSS({
    title: 'Sitename',
    description: 'RSS feed for this site',
    site_url: hostname,
    feed_url: `${hostname}/rss.xml`,
  })

  const docs = await serverQueryContent(event)
    .sort({ createdAt: 1 })
    .where({ _partial: false })
    .locale('en')
    .only(['title', 'description', 'createdAt', '_path'])
    .find()

  const posts = docs.filter((doc) => doc?._path?.includes('/posts'))

  for (const post of posts as RSSItem[]) {
    feed.item({
      title: post.title ?? '-',
      description: post.description,
      date: post.createdAt,
      url: `${hostname}${post._path}`,
    })
  }

  const feedString = feed.xml({ indent: true })
  event.node.res.setHeader('content-type', 'text/xml')
  event.node.res.end(feedString)
})

Здесь мы используем асинхронную функцию serverQueryContent для того, чтобы получить данные о существующих статьях. И там же указываем критерии для фильтрации (список всех опций фильтрации можно посмотреть в документации по ссылке в конце статьи).

В моём случае, я получаю только три поля из каждой статьи на английском языке в порядке возрастания даты.

Затем дополнительно отфильтровываю страницы по каталогу, в котором они находятся.

И в конце я добавляю данные в парсер библиотеки node-rss, чтобы сформировать окончательный код страницы.

Проверка на валидность

После того как каналы RSS созданы, нужно обязательно их проверить на корректность с помощью онлайн валидатора. И конечно же загрузить ленту в любимый клиент RSS, чтобы окончательно удостовериться, что всё в порядке.

В итоге

На своём сайте я создал два RSS канала: один для английской, второй — для русской версии. Они находятся на разных адресах и различаются только фильтром по текущей локали .locale('en').

Для того чтобы фильтр локали в Nuxt Content работал, её нужно корректно настроить. Об этом я напишу в следующий раз.


Ссылки:

Последнее обновление: