ebiken

Gatsbyでブログを作りました

2019/11/21 01:00

こんにちは、ebikenです。

1年くらい前に作ったポートフォリオサイトを作り直してブログ機能をつけました。 色々はてなブログ、Qiita、note、Mediumとかも考えましたが、独自ドメインを使いたかったのと、フロントで遊べる場所に丁度いいなと思ったので自分で作ることにしました。

ブログ機能をつけた技術スタックや感想とかを書いていきます。

コードは公開しています。
ebkn/portfolio


技術スタック

今回はこんな感じになりました

Gatsby と Now について軽く紹介します

Gatsby

Gatsby

gatsbyjs.org
GitHub

Gatsby is a free and open source framework based on React that helps developers build blazing fast websites and apps

Gatsbyは、Reactベースで作成されている爆速サイトを作るフレームワークです。
プラグインを入れることでMarkdownのパーサーやPWA対応などをいれることができます。

plugins

有名なサイトでの採用事例も結構あり、ブログサイトだと有名な overreacted.io もGatsbyで作られています
どういう仕組みで動いているのかわかりやすく解説してくれている記事があったので貼っておきます

Now

Now

zeit.co/home
GitHub

All-in-one solution for static & JAMstack deployment for performance-obsessed teams.

Now は、Zero config の静的サイトホスティングサービスです。
証明書の設定や独自ドメインの指定、CD(GitHubなどと連携)もあり、個人で使う分には無料で使うことができると思います。

主にやったこと

  • Markdown でブログを書く
  • コードの syntax highlight
  • ダークモード
  • PWA 化(オフライン対応)
  • Gatsby の TypeScript 対応
  • CI - GitHub Actions
  • CD - Now

Markdownでブログを書く + コードのsyntax highlight

/content/blog/${title}/index.md に記事を書くと /blog/${title} に追加されるようにしました。
gatsby-starter-blog のコードを参考に実装しました。
Syntax Highlight は gatsby-remark-prismjs で導入しており、プラグインで用意されているテーマ(数が少ない)を使うか、prismjs用に書かれたCSSを探してくるのが良さそうです。ドキュメントには gatsby-browser.jsrequire してと書いてありますが、自分はlight/darkモードでスタイルを分けたかったので layout.tsx に書いています。

gatsby-remark-prismjs

prismjs

ダークモード

右上のアイコンをクリックするとlight/darkモードのスタイルを切り替えるようにしました。
最初は dark-mode-toggle を使ってやろうとしてたんですが、Reactコンポーネントで状態管理したかったので使いませんでした。ダークモードが有効になっているブラウザでは prefers-color-scheme を見るようにしたり、状態を localstorageに入れて保持するようにもしました。

if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  // dark mode
}

スタイルは layout.tsx に書き、 body.light/body.dark セレクタに CSS Variables で色を定義しています。
また、色を切り替える関数は React Context で定義して子コンポーネントから変更できるようにしました。

body.light {
  --bg-color: #FAFAFA;
  ...
}
body.dark {
  --bg-color: #212121;
  ...
}
const DarkModeToggleButton: React.FC<{}> = () => {
  const toggle = useContext<DarkModeToggleContextType>(DarkModeToggleContext);
  return <button onClick={toggle}>;
};

このあたりが参考になりました。

Gatsby の TypeScript 対応

公式のプラグイン gatsby-plugin-typescript を入れるだけでTypeScriptで書けるようになります。すごく楽でした。
また、Gatsbyはサーバーで用意したコンテンツ(metaタグ、ブログの投稿など)の配信に GraphQL を使用しており、それを /page 以下のファイルに pageQuery という形で書くことで props から取得することがなっています。
この型定義は自動生成したいので、 gatsby-plugin-graphql-codegen というプラグインを使用しました。

// gatsby-config.js
...
{
  resolve: 'gatsby-plugin-graphql-codegen',
  options: {
    fileName: 'types/gql.d.ts',
  },
},
...

これで型は生成されるのですが、 type Maybe<T> = T | null が大量に含まれているので、最近TypeScriptに入った Optional Chaining をいれました。 npm i -D @babel/plugin-proposal-optional-chaining して .babelrc に以下を書くと使えます。

{
  "plugins": [
    "@babel/plugin-proposal-optional-chaining"
  ],
  "presets": [
    "babel-preset-gatsby"
  ]
}

Optional Chaining についてはここを参考にしました

PWA化(オフライン対応)

基本的にはGatsbyの gatsby-plugin-offline, gatsby-plugin-manifest プラグインを入れるだけで設定できるのでかなり楽でした。
Service Worker (gatsby-plugin-offline プラグインは Workbox でラップされている)の挙動をカスタマイズしたい場合は自分で sw.js を書いて指定することもできます。

// sw.js
if (workbox) {
  workbox.precaching.precacheAndRoute(self.__precacheManifest || []);
  workbox.googleAnalytics.initialize();
  workbox.routing.registerRoute(
    /.js/,
    new workbox.strategies.NetworkFirst(),
  );
  workbox.routing.registerRoute(
    /\.(?:png|gif|jpg|jpeg|svg|ico)$/,
    new workbox.strategies.CacheFirst({
      cacheName: 'images',
      plugins: [
        new workbox.expiration.Plugin({
          maxEntries: 60,
          maxAgeSeconds: 30 * 24 * 60 * 60,
        }),
      ],
    }),
  );
} else {
  console.log('failed to load workbox');
}

CI/CD - GitHub Actions + Now

CI は GitHub Actions で構築しました。ちょうど1週間前くらいにβが外れて正式版になり触らなきゃと思ってたので、サクッと学べて丁度良かったです。GitHub公式のCIなのでGitHubで完結してくれるのは良いです。

---
name: main

on: [push]

jobs:
  build:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-node@v1
        with:
          node-version: 12
      - name: cache node_modules
        uses: actions/cache@v1
        with:
          path: node_modules
          key: npm-packages-${{ hashFiles('package-lock.json') }}
          restore-keys: |
            npm-packages
      - run: npm install
      - run: npm run build

CD は Now の GitHub integration という機能を使ったのですが、これが最高でした。default branch に設定されているブランチにコミットされると自動で production デプロイが走り、それ以外のブランチは staging デプロイがされプレビュー用のURLがPRに貼られます。
ほとんど設定すること無くこれが使えるのは凄いです。

Now staging deployment GitHub screen shot


Gatsby, Now, GitHub Actions あたりが人気だったので気になっていましたが、実際触ってみて結構良かったので布教していきます。

今後の機能追加はこのあたりをやる予定です。また、さらに良いやつがでてきたらどんどん作り変えて行こうと思ってます。

  • textlint の導入
  • OGP用画像の生成
  • RSS feed の設定

作業ログとか下書きは Scrapbox に書いています