Hashnode & Astro
Hashnode est un CMS hébergé qui vous permet de créer un blog ou une simple publication.
Intégration avec Astro
L'API publique de Hashnode est une API GraphQL qui vous permet d'interagir avec Hashnode. Ce guide utilise graphql-request, un client GraphQL minimal qui fonctionne bien avec Astro, pour apporter vos données Hashnode dans votre projet Astro.
Prérequis
Pour commencer, vous devez disposer des éléments suivants :
Un projet Astro - Si vous n'avez pas encore de projet Astro, notre guide d'installation vous permettra d'être opérationnel en un rien de temps.
Un site Hashnode - Vous pouvez créer un site personnel gratuit en visitant Hashnode.
Installation des dépendances
Installez le paquet graphql-request en utilisant le gestionnaire de paquets de votre choix :
npm install graphql-request
pnpm add graphql-request
yarn add graphql-request
Créer un blog avec Astro et Hashnode
Ce guide utilise graphql-request, un client GraphQL minimal qui fonctionne bien avec Astro, pour apporter vos données Hashnode dans votre projet Astro.
Prérequis
- Un blog Hashnode
- Un projet Astro intégré avec le paquet graphql-request installé.
Cet exemple va créer une page d'index qui liste les articles avec des liens vers des pages individuelles générées dynamiquement.
Récupération des données
Pour récupérer les données de votre site avec le paquet
graphql-request, créez un répertoiresrc/libet créez deux nouveaux fichiersclient.ts&schema.ts:Répertoiresrc/
Répertoirelib/
- client.ts
- schema.ts
Répertoirepages/
- index.astro
- astro.config.mjs
- package.json
Initialisez une instance API avec GraphQLClient en utilisant l'URL de votre site web Hashnode.
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}") { id title posts(first: 20) { pageInfo{ hasNextPage endCursor } edges { node { id author{ name profilePicture } title subtitle brief slug coverImage { url } tags { name slug } publishedAt readTimeInMinutes } } } } } ` ); 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}") { id post(slug: $slug) { id author{ name profilePicture } publishedAt title subtitle readTimeInMinutes content{ html } tags { name slug } coverImage { url } } } } `, { slug: slug } ); return data.publication.post; };Configurez
schema.tspour définir la forme des données renvoyées par l'API Hashnode.import { z } from "astro/zod"; export const PostSchema = z.object({ id: z.string(), 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({ id: z.string(), 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({ id: z.string(), 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>
Affichage d'une liste d'articles
La récupération via getAllPosts() renvoie un tableau d'objets contenant les propriétés de chaque article telles que :
title- le titre de l'articlebrief- l'affichage HTML du contenu de l'articlecoverImage.url- l'URL source de l'image vedette de l'articleslug- le nom de l'article.
Utilisez le tableau posts renvoyé par la récupération pour afficher une liste d'articles de blog sur la page.
---
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}`}>Lire la suite</a>
</div>
))
}
</body>
</html>Générer des pages
Créez la page
src/pages/post/[slug].astropour générer dynamiquement une page pour chaque article.Répertoiresrc/
Répertoirelib/
- client.ts
- schema.ts
Répertoirepages/
- index.astro
Répertoirepost/
- [slug].astro
- astro.config.mjs
- package.json
Importez et utilisez
getAllPosts()etgetPost()pour récupérer les données de Hashnode et générer des routes de pages individuelles pour chaque article.--- 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); ---Créez le modèle pour chaque page en utilisant les propriétés de chaque objet
post. L'exemple ci-dessous montre le titre de l'article et le temps de lecture, puis le contenu complet de l'article :--- 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="fr"> <head> <title>{post.title}</title> </head> <body> <img src={post.coverImage.url} alt={post.title} /> <h1>{post.title}</h1> <p>{post.readTimeInMinutes} mins de lecture</p> <Fragment set:html={post.content.html} /> </body> </html>:::note
<Fragment />est un composant Astro intégré qui vous permet d'éviter un élément enveloppant inutile. Cela peut s'avérer particulièrement utile lorsque vous récupérez du HTML à partir d'un CMS (par exemple, Hashnode ou WordPress).:::
Publier votre site
Pour déployer votre site, consultez notre guide de déploiement et suivez les instructions de votre hébergeur préféré.
Ressources communautaires
astro-hashnodesur GitHub
Plus de guides sur les CMS
CMS partenaires mis en avant
-
CloudCannon
CMS reposant sur Git, conçu pour la rapidité, la sécurité et une utilisation sans tracas.