Lecciones del curso

Aprende Remix construyendo un Blog con MongoDB y Netlify

Clonando el proyecto
2m
Anatomía del proyecto
4m
Agregando TailwindCSS
3m
Creando y conectando con la base de datos
8m
Ruta para el login
Maquetando el dashboard
Editando posts | Primera parte
Editando posts | Segunda parte
Preparando el UI público
Redireccionando en la Página de inicio
Vista de lista
CSS para el Markdown
Blog listo para producción con Netlify
Creando Feedlinks (SSR)
Creando un sitemap.xml
Felicitación y despedida

Agregando una ruta SSR feed

Para un blog es esencial que los motores de búsqueda puedan indexar correctamente cada uno de los posts de nuestro blog, para que lo ofrescan como resultado a una búsqueda. ✅

Los blogs más exitosos son aquellos que tienen temas evergreen es decir, que las búsquedas no dependen de una moda o tendencia, sino de conceptos más permanentes, de temas fundamentales. Se podrían comparar estos dos títulos para ejemplificar:

S_erverless functions con Netlify_ 📸 // Tendencia

vs

Cómo escribir un loop en JS. // Evergreen

Si queremos que nuestro blog tenga tráfico orgánico y no tener que gastar nuestros ahorros en marketing, bueno, necesitamos que Google sepa que nosotros tenemos respuestas a las búsquedas de los usuarios y de paso que sepa que tenemos herramientas para actualizar sobre las novedades, a nuestros seguidores (RSS). Si Google sabe esto, nos favorecerá. 🫱🏼‍🫲🏾

Creando un RSS

Podríamos escribir mucho XML a mano, lo que te haría maldecirme y preguntarte: ¿Pa qué estoy escribiendo todo este XML, si ya nadie usa RSS? Es más, ni sé que significa tener un feed, ¡maldito blissmo!

Seguro que dirías algo así, ¿no?. 😜

Pero para evitar lo anterior, vamos a usar una pequeña herramienta que viene bien en estos casos y nos evita tener que escribir XML. 😎

npm i feed

Una vez instalada, vamos a escribir una función interesante que nos ayudará con 3 formatos diferentes (JSON, ATOM1 y RSS2).

Nunca sabes quién lo necesitará para incluir tu contenido y enlistarlo en su propio sitio o simplemente seguir tus publicaciones de cerca con un cliente RSS.

No olvides que hay bots por todas partes, nos vigilan… 🤖

👀 Sí, queremos toda la difusión posible

Veamos cómo usaremos Feed.

// app/utils/feed.server.ts import { Feed } from "feed"; import { db } from "~/utils/db"; const generateFeed = async () => { const feed = new Feed({ title: "Blissmo blog", description: "¡Mantente notificado de nuevos posts!", id: "<https://curso-blog-remix.netlify.app>", link: "<https://curso-blog-remix.netlify.app>", language: "es", // optional, used only in RSS 2.0, possible values: <http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes> image: "<https://i.imgur.com/LywcMSq.png>", favicon: "<https://i.imgur.com/nVMrb56.png>", copyright: "All rights reserved 2023, Héctorbliss", updated: new Date(2023, 6, 24), // optional, default = today feedLinks: { json: "<https://curso-blog-remix.netlify.app/json>", atom: "<https://curso-blog-remix.netlify.app/atom>", rss: "<https://curso-blog-remix.netlify.app/rss2.xml>", }, author: { name: "Héctorbliss", email: "fixtergeek@gmail.com", link: "<https://hectorbliss.com>", }, }); // Conseguimos los posts de la DB const posts = await db.post.findMany({ where: { published: true }, include: { author: true }, }); // Usamos un forEach para agregar con feed.addItem posts.forEach((post) => { feed.addItem({ title: post.title, id: `https://curso-blog-remix.netlify.app/blog/${post.slug}`, link: `https://curso-blog-remix.netlify.app/blog/${post.slug}`, description: post.body.slice(1, 30), content: post.body, author: [ { name: post.author.name ?? "", email: post.author.email, link: post.author.email, }, ], contributor: [ { name: "Brenda Ortega", email: "brenda@fixter.org", link: "<https://www.brendago.design/>", }, ], date: post.createdAt, image: post.cover ?? "", }); }); return feed; }; // No dejes de tipar todo lo que puedas y entiendas export const getFeed = async ( type: "atom1" | "rss2" | "json1" = "rss2" ): Promise<string> => { const feed = await generateFeed(); return type === "rss2" ? feed.rss2() : type === "atom1" ? feed.atom1() : feed.json1(); };

Recuerda cambiar este código con tus datos. ☑️

Creando las rutas

Toma nota de el punto en el nombre del archivo. Estos corchetes nos ayudan a incluir un [.] en el nombre, sin que sea tomado como un divisor de segmento o el inicio de la extensión.

Llamaremos a estas rutas, feedLinks.

Comencemos con el primer archivo.

// app/routes/feed[.]xml import { type LoaderFunction } from "@remix-run/node"; import { getFeed } from "~/utils/feed.server"; export const loader: LoaderFunction = async () => { const feed = await getFeed("rss2"); return new Response(feed, { headers: { "Content-Type": "application/rss+xml; charset=utf-8", "x-content-type-options": "nosniff", }, }); };

👀 x-content-type-options Indica que el MIME type debe ser respetado.

Agregando dos rutas más

Necesitamos otras dos rutas porque, ya que feed nos regala otros dos formatos, bueno, ¿por qué no usarlos?

// app/routes/feed[.]atom import { type LoaderFunction } from "@remix-run/node"; import { getFeed } from "~/utils/feed.server"; export const loader: LoaderFunction = async () => { const feed = await getFeed("atom1"); return new Response(feed, { headers: { "Content-Type": "application/atom+xml; charset=utf-8", "x-content-type-options": "nosniff", }, }); };

Finalmente la ruta para JSON que es el formato más moderno, utilizado en APIs de todo el mundo.

// app/routes/feed[.]json import { type LoaderFunction } from "@remix-run/node"; import { getFeed } from "~/utils/feed.server"; export const loader: LoaderFunction = async () => { const feed = await getFeed("json1"); return new Response(feed, { headers: { "Content-Type": "application/json; charset=utf-8", "x-content-type-options": "nosniff", }, }); };

Visita cada una de tus nuevas rutas y comprueba que tus feed funcionan. 🤓 🔥 🕺🏻

No más cervezas. Bueno, una, nomás pa celebrar que tenemos el SEO completamente cubierto. 🎉 🍻 🥳

Enlaces relacionados

W3C feed validator: W3C Feed Validation Service, for Atom and RSS

¿Qué es un RSS? RSS

Remix cache: Performance

spaceman

¿List@ para ver todo el curso? Prepárate porque apenas estamos comenzando 🚀

¡Desbloquea el curso completo y conviértete en un PRO del desarrollo web! 🫶🏻 .