ポートフォリオサイトをGatsbyJSでリニューアルしました

元号が変わり令和を迎えた昨今、皆様いかがお過ごしでしょうか。

自分は「ゴールデンウィークもう半分過ぎたの? 早すぎるのでは???」という気持ちでいっぱいです。

連休始まってから、まだ3日くらいしか経ってない気がする……

📋 ポートフォリオサイト

ゴールデンウィークに目標としていたことのひとつに「ポートフォリオサイトをリニューアルする」というのがありました。

実はブログの他にポートフォリオサイトも作ってあったんですが、こいつも以前のブログと同じくWordPressで作っていたので、いい加減なんとかしようと思ったわけです。

ブログと比べてコンテンツが少なく移行が簡単そうだったのと、タイルデザインでSPAっぽかったのでGatsbyJSを使って作り直すことにしました。

そんなわけでこんな見た目のサイトになりました。

portfolio.png (3.1 MB)

記事の管理はNetlify CMSからできるようにしています。

16a734eaca8b66b9944b4286.png (474.0 kB)

こんな感じで記事が一覧できるし、

16a734f010b85cbee38f8cec.png (152.9 kB)

こんな感じで記事を作ったり手直ししたりできます。便利!

実際に手を動かしたのは昨日と今日の2日間くらいなので、割とさっくり作れたんじゃないかなーと思います。

🎨 デザイン

基本的なテーマはgatsby-starter-portfolio-emmaを使っています。

ただデモサイトを見てもらうとわかるんですが、このデザインの詳細ページでは画像が背景になっています。

作りたかったのは以下のように、作品画像が独立して表示されるもの。

16a735644fbec29a26a6d52f.png (879.6 kB)

そんなわけでここを手直しする必要があったんですが、gatsby-imageのFluidとFixedの概念にだいぶ苦しめられました。多分作業時間の半分はここと戦ってます。

もともとはFluidだったんですが、ここはFixedにしないと変なふうにトリミングされたり拡大されたりしてしまいました。

そしてFixedにすると、今度は中央寄せがうまくいかない……

最終的に、以下のようにコンテナになるdivのwidthを無理やり100%にしたうえで、IMGのほうはobject-fitをcontainにすることで中央寄せにできました。

.gatsby-image-wrapper {
  width: 100% !important;
  margin: 5px auto;
}
<Img fixed={project.cover.childImageSharp.fixed} objectFit="contain" alt=""/>

!important;を使ったので負け感がすごいですが、なんとか実現できたのでよしとします。

⚙️ Netlify CMS

先述のとおり、コンテンツの管理にはNetlify CMSを使っています。

これはAdd to Your Siteに従ったらサクッとできたんですが、画像だけはfrontmatterで相対パスになってほしいところが絶対パスになってしまい、うまく動きませんでした。

んでググってみるとNetlify cms with GatsbyJs image upload path problemsだのQuestion: How to use image processing for images uploaded via Netlify CMS?だの、Issueがどんどん出てくる。

どうもNetlify CMSとしては、アップロードしたイメージがそのままpublicになって、Markdownからもそれを直接見る前提の設計になっており、Gatsbyのように相対パスで見つけて前処理をかけるのは想定していないっぽいです。

gatsby-remark-relative-imagesあたりでできそうだったんですがうまく動かず。しょうがないのでこのworkaroundを元に、以下のようにgatsby-node.js内でパスを書き換えるコードを入れました。

exports.onCreateNode = ({ node, actions, getNode }) => {
  // workaround: fix image url
  const { frontmatter } = node
  if (frontmatter) {
    const { cover } = frontmatter
    if (cover) {
      if (cover.indexOf('/images') === 0) {
        node.frontmatter.cover = `./../../static` + frontmatter.cover
      }
    }
  }
  // ...

ちなみに、相対パスで掘る場合でもgatsby-source-filesystemで見られる場所にしてあげないとうまく動かないようです。(これで数時間ハマった)

このためgatsby-config.jsで以下のようにimagesの場所を教えてあげます。

module.exports = {
  plugins: [
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'images',
        path: `${__dirname}/static/images`,
      },
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'projects',
        path: `${__dirname}/content/projects`,
      },
    },
    // ...

こんな感じで、Netlify CMSからアップロードした画像もうまく扱えるようになりました。

🌏 DNS設定

ポートフォリオサイトは kokuyouwind.comwww.kokuyouwind.com で見れるようにしたかったんですが、お名前.comではルートドメインではCNAME設定ができず……

以前はVPNのIPアドレスを直接指定していたんですが、NetlifyではSSL証明書絡みがだいぶ怪しいのでAレコードでの指定は避けたい。

Route53でも簡単にはできなさそうなのでどうしたもんかと思っていたんですが、Netlify DNS使えば簡単にできるらしいので試してみることに。

そしたらNetlifyで作ったサービスは自動でCNAME登録されるし、ルートドメインもちゃんとNetlifyに向けれるし、他のレコードも自由に設定できるし、と一瞬ですべての問題が解決しました。

これ無料プランでも使えるの凄いですね…… 一応有料プランだとセカンダリDNSが使えるようになるらしいですが。

🤔 課題

もともとあったカテゴリでの絞り込みができなくなってしまったので、これは後で追加したいです。 index.jsxとほぼ同じテンプレートでGraphQLだけちょっと書き換えて、カテゴリごとにcreatePageすれば行けるはず……

あとは、モバイルだと1列表示になるうえ、マウスホバーという概念がないためタイトルが表示されずUXが最悪でした…… できればなんとかしたい……

📝 感想

GatsbyJS、適当に書いたマークダウンがそのまま静的なSPAサイトになるのはすごいです。

ただGraphQLを使ったクエリの書き方が難しかったり、JSXとGraphQLで型が合わないとエラーの出方が不親切だったりと、覚えることが多くなかなか難しいです。

あと画像のハンドリングも、ビルド時にいろいろうまくやってくれる反面どうなってるか分かりづらい部分が多く、一度ハマるとデバッグに苦労する印象です。

とはいえこのシステムをNuxt.jsなどで自作しようと思ったら結構めんどくさそうなので、うまく乗っかれれば短期間で爆速サイトを作れそうな感じはあります。

せっかく作ったので、今後も保守しつつGatsbyJSを使いこなせるようになっていこうと思います。

💬 余談

平成のうちにポートフォリオサイトを作り直して「平成にやってきたことを振り返りました!」ってやるつもりだったんですが、間に合いませんでした🙈

せっかくリニューアルしたので昔ニコニコに上げた動画とかも掘り起こしたところ、学生時代に作った動画だらけで老を感じたのと、黒歴史も混じってて悶絶したりしました。

著作権的なアレがだいぶ怪しいやつもありますが、まぁ若気の至りということでご容赦ください🙇