Next.js (SSG) & flux RSS

Publié il y a environ 1 an~3 min

Face à la multiplication des contenus en ligne, l'accès à l'information peut parfois s'avérer plus chronophage qu'on ne le souhaiterait... Qu'il s'agisse d'actualités générales ou plus ciblées, il existe pourtant un moyen simple de faciliter sa veille quotidienne : les flux RSS.

Alors pourquoi ne pas en mettre un en place sur son site web (statique), et gagner ainsi en visibilité ?

Sur la base d'un projet Next.js (SSG), nous allons voir comment ajouter simplement un flux RSS pour des articles rédigés en Markdown.

Pré-requis

  1. Node.js (>= 10.13)
  2. Un projet Next.js (existant ou généré via npx create-next-app)

Ce site web a servi de base à cet article, n'hésitez donc pas à vous référer au code source pour plus de détails !

Générer le flux RSS

S'il est tout à fait possible de générer le(s) fichier(s) de flux de façon complètement manuelle, il n'est pas pour autant nécessaire de réinventer la roue ! :man-cartwheeling: Ici, nous nous appuierons donc sur le package feed, qui simplifiera l'écriture de notre fonction de génération de flux :

1import fs from 'fs'
2import { Feed } from 'feed'
3import { remark } from 'remark'
4import html from 'remark-html'
5import gemoji from 'remark-gemoji'
6
7import { LOCALES } from '@i18n/constants'
8import { getPosts } from '@api/posts'
9import { getI18n } from '@api/i18n'
10
11const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL
12const AUTHOR_NAME = process.env.NEXT_PUBLIC_SITE_NAME
13const TWITTER_USERNAME = process.env.NEXT_PUBLIC_TWITTER_USERNAME
14
15const markdownToHtml = (markdown) =>
16 remark().use(html).use(gemoji).processSync(markdown).toString()
17
18const generateRssFeed = () => {
19 const author = {
20 name: AUTHOR_NAME,
21 link: `https://twitter.com/${TWITTER_USERNAME}`,
22 }
23
24 LOCALES.forEach((lang) => {
25 const { description } = getI18n(lang, 'home').home
26
27 const feed = new Feed({
28 title: `${AUTHOR_NAME}'s blog feed`,
29 description: Object.values(description).join(' '),
30 id: `${SITE_URL}/${lang}`,
31 link: `${SITE_URL}/${lang}`,
32 language: lang,
33 generator: 'Next.js using Feed',
34 feedLinks: {
35 rss2: `${SITE_URL}/${lang}/feed.xml`,
36 },
37 author,
38 })
39
40 const posts = getPosts(['title', 'excerpt', 'content'], lang)
41
42 posts.forEach((post) => {
43 feed.addItem({
44 title: post.title,
45 id: `${SITE_URL}/${lang}/blog/${post.slug}`,
46 link: `${SITE_URL}/${lang}/blog/${post.slug}`,
47 description: post.excerpt,
48 content: markdownToHtml(post.content),
49 date: new Date(post.date),
50 author: [author],
51 })
52 })
53
54 fs.mkdirSync(`./public/${lang}`, { recursive: true })
55 fs.writeFileSync(`./public/${lang}/feed.xml`, feed.rss2(), 'utf8')
56 })
57}
58
59generateRssFeed()

Le code se découpe en deux parties, assez simples : on génère le flux avec ses informations générales, puis on boucle sur nos contenus (posts) pour générer nos items.

L'ensemble est ensuite écrit dans un fichier .xml, au format RSS 2.0. Plusieurs formats sont possibles, néanmoins son excellent support rend l'ajout d'autres formats souvent superflu.

Nos contenus sont ici rédigés en Markdown. En s'appuyant sur l'écosystème remark, on pourra ainsi assez facilement ajouter à nos items de flux le contenu (exhaustif) de nos articles, converti au format HTML. C'est souvent une pratique recommandée, bien que non nécessaire.

Enfin, dans le cas d'un site multilingue, il suffira d'adapter le code, pour générer autant de fichier que de langues supportées.

Aider les robots

Pour faciliter la vie des navigateurs et autres robots d'indexation, et les aider à trouver notre flux RSS, il faudra penser à ajouter dans le <head /> de notre document, un lien vers celui-ci :

1<link
2 rel="alternate"
3 type="application/rss+xml"
4 title={`${AUTHOR_NAME}'s blog feed`}
5 href="/feed.xml"
6/>

Mise à jour du script de build

Maintenant que tout est en place, il reste encore à faire l'appel à cette fonction. Dans le cadre d'un site SSG, cet appel se fera, en toute logique, au moment de la phase de build.

Notre script utilise les modules ES (ESM), en partie pour permettre l'import de fonctions utilisées ailleurs dans le projet (comme celles de la récupération des contenus). Pour l'utiliser en CLI, il faut donc dans un premier temps, adapter notre configuration Webpack, via le fichier next.config.js :

1module.exports = {
2 // ...
3
4 webpack: (config, { dev, isServer }) => {
5 if (!dev && isServer) {
6 const originalEntry = config.entry;
7
8 config.entry = async () => {
9 const entries = await originalEntry()
10
11 // These scripts can import components from the app
12 // and use ES modules
13 return { ...entries, 'scripts/rss-generate': './src/scripts/rss.js' }
14 }
15 }
16
17 return config
18 }
19}

Notre script sera ainsi compilé par Webpack dans le dossier .next/server. Il ne restera plus qu'à l'appeler via un script de notre fichier package.json, qui prendra en charge la génération de notre RSS :

1"scripts": {
2 // ...
3 "build": "next build && npm run rss:generate",
4 "rss:generate": "node ./.next/server/scripts/rss-generate"
5}

🎉

Et voilà ! L'ajout d'un flux RSS est un véritable plus pour un site web (en particulier un blog ou autre site d'actualités), permettant aux utilisateurs de suivre vos contenus de façon simple, sans avoir à jongler entre une multitide d'onglets... C'est en outre un bon moyen d'améliorer sa visibilité en ligne, alors pourquoi se priver ? 🙂