Hashnode & Astro
Hashnode es un CMS alojado que te permite crear un blog o publicación.
Integración con Astro
Sección titulada Integración con AstroLa API Pública de hashnode es una API GraphQL que te permite interactuar con Hashnode. Esta guía utiliza graphql-request
, un cliente GraphQL minimalista que funciona bien con Astro, para traer tus datos de Hashnode a tu proyecto de Astro.
Prerrequisitos
Sección titulada PrerrequisitosPara comenzar necesitarás tener lo siguiente:
-
Un proyecto de Astro - Si aún no tienes un proyecto de Astro, nuestra Guía de Instalación te ayudará a empezar en poco tiempo.
-
Un sitio en Hashnode - Puedes crear un sitio personal gratuito visitando Hashnode.
Instalando dependencias
Sección titulada Instalando dependenciasInstala el paquete graphql-request
usando el gestor de paquetes de tu elección:
npm install graphql-request
pnpm add graphql-request
yarn add graphql-request
Haciendo un blog con Astro y Hashnode
Sección titulada Haciendo un blog con Astro y HashnodeEsta guía usa graphql-request
, un cliente GraphQL minimalista que funciona bien con Astro, para traer tus datos de Hashnode a tu proyecto de Astro.
Requisitos Previos
Sección titulada Requisitos Previos- Un blog de Hashnode.
- Un proyecto de Astro integrado con el paquete graphql-request instalado.
Este ejemplo creará una página de índice que lista las publicaciones con enlaces a páginas individuales generadas dinámicamente.
Obteniendo Datos
Sección titulada Obteniendo Datos-
Para obtener los datos de tu sitio con el paquete
graphql-request
, crea un directoriosrc/lib
y crea dos archivos nuevos:client.ts
&schema.ts
:Directorysrc/
Directorylib/
- client.ts
- schema.ts
Directorypages/
- index.astro
- astro.config.mjs
- package.json
-
Inicializa una instancia de API con GraphQLClient utilizando la URL de tu sitio web de Hashnode.
src/lib/client.ts import { gql, GraphQLClient } from "graphql-request";import type { AllPostsData, PostData } from "./schema";export const getClient = () => {return new GraphQLClient("https://gql.hashnode.com")}const myHashnodeURL = "astroplayground.hashnode.dev";export const getAllPosts = async () => {const client = getClient();const allPosts = await client.request<AllPostsData>(gql`query allPosts {publication(host: "${myHashnodeURL}") {titleposts(first: 20) {pageInfo{hasNextPageendCursor}edges {node {author{nameprofilePicture}titlesubtitlebriefslugcoverImage {url}tags {nameslug}publishedAtreadTimeInMinutes}}}}}`);return allPosts;};export const getPost = async (slug: string) => {const client = getClient();const data = await client.request<PostData>(gql`query postDetails($slug: String!) {publication(host: "${myHashnodeURL}") {post(slug: $slug) {author{nameprofilePicture}publishedAttitlesubtitlereadTimeInMinutescontent{html}tags {nameslug}coverImage {url}}}}`,{ slug: slug });return data.publication.post;}; -
Configura un
schema.ts
para definir la estructura de los datos devueltos por la API de hashnode.src/lib/schema.ts import { z } from "astro/zod";export const PostSchema = z.object({author: z.object({name: z.string(),profilePicture: z.string(),}),publishedAt: z.string(),title: z.string(),subtitle: z.string(),brief: z.string(),slug: z.string(),readTimeInMinutes: z.number(),content: z.object({html: z.string(),}),tags: z.array(z.object({name: z.string(),slug: z.string(),})),coverImage: z.object({url: z.string(),}),})export const AllPostsDataSchema = z.object({publication: z.object({title: z.string(),posts: z.object({pageInfo: z.object({hasNextPage: z.boolean(),endCursor: z.string(),}),edges: z.array(z.object({node: PostSchema,})),}),}),})export const PostDataSchema = z.object({publication: z.object({title: z.string(),post: PostSchema,}),})export type Post = z.infer<typeof PostSchema>export type AllPostsData = z.infer<typeof AllPostsDataSchema>export type PostData = z.infer<typeof PostDataSchema>
Mostrando una lista de publicaciones
Sección titulada Mostrando una lista de publicacionesObtener mediante getAllPosts()
devuelve un array de objetos que contiene las propiedades de cada publicación, tales como:
title
- El título de la publicaciónbrief
- La representación HTML del contenido de la publicacióncoverImage.url
- La URL de origen de la imagen destacada de la publicaciónslug
- El slugh de la publicación
Utiliza el array posts
que devuelve la consulta para mostrar una lista de publicaciones de blog en la página.
---import { getAllPosts } from '../lib/client';
const data = await getAllPosts();const allPosts = data.publication.posts.edges;
---
<html lang="en"> <head> <title>Astro + Hashnode</title> </head> <body>
{ allPosts.map((post) => ( <div> <h2>{post.node.title}</h2> <p>{post.node.brief}</p> <img src={post.node.coverImage.url} alt={post.node.title} /> <a href={`/post/${post.node.slug}`}>Read more</a> </div> )) } </body></html>
Generando páginas
Sección titulada Generando páginas-
Crea la página
src/pages/post/[slug].astro
para generar dinámicamente una página para cada publicación.Directorysrc/
- …
Directorylib/
- client.ts
- schema.ts
Directorypages/
- index.astro
Directorypost/
- [slug].astro
- astro.config.mjs
- package.json
-
Importa y utliza
getAllPosts()
ygetPost()
para obtener los datos de Hashnode y generar rutas de página individuales para cada publicación.src/pages/post/[slug].astro ---import { getAllPosts, getPost } from '../../lib/client';export async function getStaticPaths() {const data = await getAllPosts();const allPosts = data.publication.posts.edges;return allPosts.map((post) => {return {params: { slug: post.node.slug },}})}const { slug } = Astro.params;const post = await getPost(slug);--- -
Crea la plantilla para cada página usando las propiedades de cada objeto
post
. El ejemplo de abajo muestra el título de la publicación y tiempo de lectura, luego el contenido completo de la publicación:src/pages/post/[slug].astro ---import { getAllPosts, getPost } from '../../lib/client';export async function getStaticPaths() {const data = await getAllPosts();const allPosts = data.publication.posts.edges;return allPosts.map((post) => {return {params: { slug: post.node.slug },}})}const { slug } = Astro.params;const post = await getPost(slug);---<!DOCTYPE html><html lang="en"><head><title>{post.title}</title></head><body><img src={post.coverImage.url} alt={post.title} /><h1>{post.title}</h1><p>{post.readTimeInMinutes} min read</p><Fragment set:html={post.content.html} /></body></html><Fragment />
Es un componente integrado de Astro que te permite evitar un elemento de contenedor innecesario. Puede ser especialmente útil cuando recuperas HTML de un CMS (e.g. Hashnode o WordPress).
Publicando tu sitio
Sección titulada Publicando tu sitioPara desplegar tu sitio visita nuestra guía de despliegue y sigue las instrucciones de tu proveedor de alojamiento preferido.
Recursos de la Comunidad
Sección titulada Recursos de la Comunidadastro-hashnode
en GitHub