Hashnode 和 Astro
Hashnode 是一个托管 CMS,可让你创建博客或发布物。
¥Hashnode is a hosted CMS that allows you to create a blog or publication.
与 Astro 集成
标题部分 与 Astro 集成¥Integrating with Astro
Hashnode 公共 API 是一个 GraphQL API,允许你与 Hashnode 交互。本指南使用 graphql-request
(一个与 Astro 配合良好的最小 GraphQL 客户端)将你的 Hashnode 数据带入你的 Astro 项目。
¥The Hashnode Public API is a GraphQL API that allows you to interact with Hashnode. This guide uses graphql-request
, a minimal GraphQL client that works well with Astro, to bring your Hashnode data into your Astro project.
先决条件
标题部分 先决条件¥Prerequisites
要开始使用,你需要具备以下条件:
¥To get started you will need to have the following:
安装依赖
标题部分 安装依赖¥Installing dependencies
使用你选择的包管理器安装 graphql-request
包:
¥Install the graphql-request
package using the package manager of your choice:
npm install graphql-request
pnpm add graphql-request
yarn add graphql-request
使用 Astro 和 Hashnode 制作博客
标题部分 使用 Astro 和 Hashnode 制作博客¥Making a blog with Astro and Hashnode
本指南使用 graphql-request
(一个与 Astro 配合良好的最小 GraphQL 客户端)将你的 Hashnode 数据带入你的 Astro 项目。
¥This guide uses graphql-request
, a minimal GraphQL client that works well with Astro, to bring your Hashnode data into your Astro project.
先决条件
标题部分 先决条件¥Prerequisites
- Hashnode 博客
- 一个安装了 graphql-request 包的 Astro 项目。
此示例将创建一个索引页面,其中列出帖子以及动态生成的各个帖子页面的链接。
¥This example will create an index page that lists posts with links to dynamically-generated individual post pages.
获取数据
标题部分 获取数据¥Fetching Data
-
To fetch your site’s data with the
graphql-request
package, make asrc/lib
directory and create two new filesclient.ts
&schema.ts
:Directorysrc/
Directorylib/
- client.ts
- schema.ts
Directorypages/
- index.astro
- astro.config.mjs
- package.json
-
Initialize an API instance with the GraphQLClient using the URL from your Hashnode Website.
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}") {idtitleposts(first: 20) {pageInfo{hasNextPageendCursor}edges {node {idauthor{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}") {idpost(slug: $slug) {idauthor{nameprofilePicture}publishedAttitlesubtitlereadTimeInMinutescontent{html}tags {nameslug}coverImage {url}}}}`,{ slug: slug });return data.publication.post;}; -
Configure
schema.ts
to define the shape of the data returned from the Hashnode API.src/lib/schema.ts 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>
显示帖子列表
标题部分 显示帖子列表¥Displaying a list of posts
通过 getAllPosts()
获取将返回一个对象数组,其中包含每个帖子的属性,例如:
¥Fetching via getAllPosts()
returns an array of objects containing the properties for each post such as:
-
title
- 帖子的标题 -
brief
- 帖子内容的 HTML 渲染 -
coverImage.url
- 帖子特性图片的源 URL -
slug
- 帖子的标题
使用从获取返回的 posts
数组来显示页面上的博客文章列表。
¥Use the posts
array returned from the fetch to display a list of blog posts on the 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}`}>Read more</a> </div> )) } </body></html>
生成页面
标题部分 生成页面¥Generating pages
-
Create the page
src/pages/post/[slug].astro
to dynamically generate a page for each post.Directorysrc/
- …
Directorylib/
- client.ts
- schema.ts
Directorypages/
- index.astro
Directorypost/
- [slug].astro
- astro.config.mjs
- package.json
-
Import and use
getAllPosts()
andgetPost()
to fetch the data from Hashnode and generate individual page routes for each post.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);--- -
Create the template for each page using the properties of each
post
object. The example below shows the post title and reading time, then the full post content: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>
发布你的网站
标题部分 发布你的网站¥Publishing your site
要部署你的网站,请访问我们的 部署指南 并按照你首选托管提供商的说明进行操作。
¥To deploy your site visit our deployment guide and follow the instructions for your preferred hosting provider.
社区资源
标题部分 社区资源¥Community Resources
- GitHub 上的
astro-hashnode