Aller au contenu

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 :

  1. 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.

  2. 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

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

  1. Un blog Hashnode
  2. 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

  1. Pour récupérer les données de votre site avec le paquet graphql-request, créez un répertoire src/lib et créez deux nouveaux fichiers client.ts & schema.ts :

    • Répertoiresrc/
      • Répertoirelib/
        • client.ts
        • schema.ts
      • Répertoirepages/
        • index.astro
    • astro.config.mjs
    • package.json
  2. 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;
    };
  3. Configurez schema.ts pour 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'article
  • brief - l'affichage HTML du contenu de l'article
  • coverImage.url - l'URL source de l'image vedette de l'article
  • slug - 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

  1. Créez la page src/pages/post/[slug].astro pour 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
  2. Importez et utilisez getAllPosts() et getPost() 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);
    
    ---
  3. 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

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.

Tous les guides CMS

Contribuer Communauté Parrainer