Gatsby.jsとgqlgenでブログを作った

#Gatsby.js#gqlgen
2024/12/23
ArticleImage:01JFT54WPPZ0ET3XTKZ0JTCMRE

はじめに

最初は単にGraphQL、gRPC、ECS、New Relic etc
自分が興味のある技術トピックでHello World Enterprise Editionをやるだけのつもりだったものの
GraphQL -> ヘッドレスCMS -> ブログ
という連想ゲームの結果、ブログを作るに至りました

仕事でGoを触り始めた頃に着手して
中断を挟みながらゆっくり進めていたこともあって
初期に書いたコードは今見ると...ですが
まず何より完走できて良かったです

また
バックエンドを開発する中で欲しくなったライブラリを
自作してOSSとして公開できたことも
副次的にですがいい経験になりました

技術スタック

アーキテクチャ図

バックエンド

  • gqlgen
  • gRPC

フロントエンド

  • Gatsby.js
  • yamada-ui

DB

CockroachDB Serverless

AWS

  • API Gateway
  • ECS(on Fargate)
  • S3
  • Cloud Front
  • DynamoDB
  • Lambda
  • Cognito

IaC

  • CloudFormation
  • Terraform

O11y

  • New Relic

こだわり

CQRS/Event Sourcing

コマンドをDynamoDB、クエリをCockroachDB Serverlessとしました

ブログの更新はGraphQLのミューテーションで行い
コマンドの受付が完了(DynamoDBへのPut)した段階で即座にレスポンスを返します

コマンドを受け付けると
DynamoDB StreamによってLambdaへ連携され
記事のスナップショットをCockroachDB Serverlessに流します

実際にブログ記事やタグとして参照されているデータはこのスナップショットです

Lambdaはデータの同期が終わったタイミングで
repository dispatch API経由でGitHub Actioesを実行して
そのワークフロー内でGatsby.jsのビルド・デプロイが行われます

Grid Layout

自社のデザイン/フロントエンドの方が激推ししているのでチャレンジしてみました

本質的に理解できるまでには至らず
要所要所で雰囲気ゴリ押し実装してしまった節はあるのですが
grid-template-areasは直感的にレイアウトが組めて使っていて楽しかったです

コメント・リアクション機能

Hugoが公式にフィーチャーしていることもあってか
エンジニアのブログを見ているとDisqusが採用されている例を多く見かけました

個人的に

  • お金がかからないこと
  • モデレートしやすい
  • コメントだけでなくリアクションもできる

をMUSTとしていたため
上記に合致していたgiscusを採用しました

Gatsby.jsで困ったこと

これは何より自前のGraphQLサーバーをデータソースにする事例が殆ど見当たらなかったことです

正直この時点で手詰まりかなとも思ったのですが
外部から取得した画像をGatsbyImageで利用するTipsを参考に
マークダウン文字列からFileNodeを生成することができました

Copy
const content = `
---
id: "${articleNode.id}"
title: "${articleNode.title}"
createdAt: "${format(new Date(articleNode.createdAt), "YYYY/MM/DD")}"
updatedAt: "${format(new Date(articleNode.updatedAt), "YYYY/MM/DD")}"
tags: [${articleNode.tags.edges
        .map((edge) => {
          return `{"id": "${edge.cursor}", "name": "${edge.node.name}"}`;
        })
        .join(", ")}]
---
${rawContent}`;
const contentNode = await createFileNodeFromBuffer({
  buffer: Buffer.from(content),
  cache,
  createNode,
  createNodeId: (): string => {
    return `ArticleContent:${articleNode.id}`;
  },
  hash: createContentDigest(content),
  ext: ".md",
});

ただこれだけではMarkdownスキーマが生成されず
Gatsbyエコシステムでremarkができないため
今回は事前に下記のようなスケルトンファイルを用意することで解決しました

Copy
---
id: "Noop"
title: "Noop"
createdAt: 1970/01/01
updatedAt: 1970/01/01
tags:
  - {
    id: "Noop",
    name: "Noop"
  }
---
Noop

frontmatterフィールドを利用する場合は
スケルトンのfront matter部分も取得するデータと同様のフォーマットで定義する必要があります

今後やりたいこと

gatsby-source-miyamotoday

前述のskelton.md対応はさすがにお粗末なので
Contentful etc ヘッドレスCMSのように
専用のプラグインを作ってみたいです

投稿用のUI

この記事はGraphQLクライアントを使って投稿してます
困っていないといえば困ってないのですが
断筆する原因になりうるので何とかしたいです

通知

非同期レスポンスパターンのため
ブログ自体の更新の成功/失敗はリクエストを送った段階では分かりません
現状、成功・失敗の判断する手段はブログを見る以外にないので
RMUがGitHub Actionsをキックした段階でメール通知してくれるようにしたいです

ソースコード

参考にさせていただいたブログ


Recommend Articles

S3 + CloudFrontで実現する独自ドメインGoパッケージ

はじめに go.uber.org/mock google.golang.org/grpc gorm.io/gorm 独自ドメインで配布されているGoパッケージはカッコいい 、 のような のPrefixがない分、importディレクティブがスッキリして見える 今回は当ブログのバ…

2025/01/26

ArticleImage:01JJHA5TFHVR4MP9ZWJSDD713A

algolia+instantsearchで全文検索に対応した

はじめに gatsby-plugin-algolia と react-instantsearch を利用して当ブログに記事を全文検索できる機能を追加しました この記事含めまだ3件しか書いていないので全文検索を活用するべく2025年はブログの1年にしていきたい所存 ページのInd…

2025/01/05

ArticleImage:01JGT8DR23JG0SZ4AH5AVAMZBM

Copyright © miyamo2 All rights reserved.