2022/01/13

テックブログを作る

トラベルブックでテックブログを始めることにしました。 今回はどのようにテックブログを作ったのか。 方針、技術スタック、実装、執筆フローについて書いてみます。

テックブログを始めます

トラベルブックでスーパーバイザーをやってる yusukebe です(スーパーバイザーって聞き慣れないので「なんだそれ?」って思ったかもしれませんが、それについては今後本ブログで書いていければいいなと思います)。

さてあらためて、トラベルブックでテックブログを始めます。

今回は、なぜテックブログを始めるのかという「Why」や「What」は置いておいて、どうやって作ったかという 「How」の部分、つまりシステムの話を中心に書きます。このブログは見ての通り、たった今、始まったばかりなので、これがイケてるかどうかの判断はまだできません。でも、他社のものと比べてちょっとだけ変わった構成になっています。興味を持っていただけると思うので、このブログの「初めて」の投稿を是非読んでいってください。

はてなブログは使わない

システムの方針についてです。

クックパッドや ZOZO、一休といった大手も含めて多くの企業のテックブログではてなブログが使われています。また、はてなブログでは「はてなブログ for DevBlob」というまさに「テックブログ」に最適な専用プランが用意されています。

はてなブログを使わない手はない!

となりがちですが、我々は当初から「はてなブログは使わない」という方針を立てました。

その理由は以下の通りです。

  • はてなブログを使わないことで他と差別化を図る。
  • ブログを実験場にする。はてなブログを使わず、自前でシステムを組めば、試したい技術を実験できる。
  • ブログシステムを作ったこと自体をブログのネタにしたい。
  • プラットフォームに依存したくない。特に記事やアセットの管理について。できれば Git レポジトリで管理できたら嬉しい。
  • レビューをしたい。はてなブログでもできそうだけど、メンバーをアサインして、「XXX 行目にタイポがあるよ」といった具合により細かくレビューをしたい。
  • トラベルブックではメディアを運営しています。Core Web Vitals に代表されるサイトのパフォーマンス向上に力を入れています(どのような努力をしているかについては後ほどとあるメンバーが記事にしてくれるでしょう!)。自前ならいくらでも「速く」できます。数あるテックブログの中でも「速い」ブログを目指します。

ちなみに、今回たまたま使わないと判断しただけで、決して、はてなブログを悪く思っているわけではないです!

技術スタック

自前でシステムを組むと言っても、ブログアプリケーションをイチからコーディングしたり、サーバー立てててデプロイフローを作るのは大変なので、既存のプロダクトをいくつか組み合わせて作ります。

Hugo

まず、Hugo です。今回のブログシステムの鍵を握る Static Site Generator=SSG のフレームワークです。僕が個人のブログで使っている経験と今回実験した結果から、今のところ以下の強みがあると考えています。

  • 記事を Git で管理できる。
  • Markdown で書ける。
  • 静的ファイルを配信するので当然速い。
  • 自分たちでテンプレートをいじれる。
  • テンプレートなどのシステムも Git で管理できる。
  • ローカルでプレビューできる。
  • ビルドが速い。

特に Git で管理できるのが熱くて、GitHub のレポジトリでやればコードレビューと同じ要領で、ブログ記事をレビューできます。当然、記事やアセットを手元に持つことができ、リビジョン管理もできます。

ということでブログシステムとして Hugo を採用することにしました。

AMP

ページは AMP で作ることにしました。 厳密に言えば、AMP コンポーネントを使って、AMP Valid な HTML ページにします。

AMP については議論があり「AMP やめました」発言を昨今よく耳にしています。 とはいえトラベルブックでは一部ページを AMP で実運用しており、 その経験から「メリットも十分ある」と考えています。 AMP を導入することは Web Vitals などのパフォーマンスを向上させることに繋がります。 また、例えば amp-img が Lazy Load を賢くやってくれたりと AMP コンポーネントの出来がよいので、それを利用できるのもよいです。

通常の HTML ページと AMP ページを 2 つ用意することになると、 管理コストが発生して大変ですが、今回の場合、最初から AMP ページのみとして作ってしまうことができるのも採用するきっかけになりました。

Jamstack

次に考えなくていけないのはどうデプロイして公開するかです。Linux サーバーを立てて、Apache や Nginx でサーブするといった(古典的な)構成は取りたくありません。そこで、いわゆる Jamstack に近いものを採用しました。つまり、こういうことです。

  • ダイナミックにコンテンツを生成しない
  • 予め SSG した HTML を配信する
  • コンテンツを CDN に置く
  • サーバーレス

Jamstack の「J」は JavaScript の「J」ですが、今回は JavaScript を使いません。また「a」は「API」の「a」です。ですので今回のシステムは厳密には Jamstack ではないのですが、それに近いものです。Jamstack にすると何がいいかというと、いくつかありますが、特にパフォーマンス面についてのアドバンテージです。当初から掲げていた我々の方針「サイトを速くしたい」とマッチします。

Vercel

Jamstack のプラットフォームとして Vercel を選びました。似たようなものに Netlify、Cloudflare Pages などあります。これら Jamstack 向けのプラットフォームは以下のような特徴があり、今回のユースケースと非常に相性がよいです。

  • GitHub のレポジトリと連動する。
  • サービス上でビルドを行える。
  • ビルドからデプロイまで自動でやってくれる。
  • Hugo に対応している。
  • CDN で配信される。
  • レポジトリの push や Web hook などをフックにできる。
  • 本番と開発用の環境がある。
  • デプロイごとにプレビュー用の URL を発行してくれる。

特に Vercel は

  • 日本に CDN エッジがあって速い。
  • チームの管理がしやすい。
  • Hugo は対応していないが Analytics など面白い試みをしている
  • なんかかっこいい。

という理由から採用しました。最後の「なんかかっこいい」は重要です。

GitHub Actions

Vercel はビルドからデプロイまでやってくれます。 なので、記事を書いた人が GitHub のレポジトリに push。 それをフックとして、Vercel がビルド・デプロイというフローを思い描いていました。

ところで、Vercel の料金体系は「1 メンバーにつき$20」となっています。 なので、なるべくメンバーを少なくして、運用したいところ。 ブログを書く全員をメンバーに入れると高くつくので現実的じゃありません。 最初は僕だけがメンバーならいいと思っていました。

しかし 試してみると、Vercel のメンバーが GitHub に push をしなくては、ビルドが走らないことが分かりました。毎度、唯一のメンバーである僕がデプロイしなくてはいけません。 これはめんどい。そこでいい方法がないかと探った答えが GitHub Actions です。 GitHub Actions のマーケットプレイスにある「Vercel Action」を使いました。

この場合、ビルドは GitHub Actions 上で行われます。 そして、できた HTML ファイル等が Vercel にアップロードされます。

Vercel に対してデプロイを行うが GitHub Actions なので、記事を書く人は必ずしも Vercel のメンバーでなくてよくなりました。

以上、

  • Hugo - ブログシステム
  • AMP - Web のコンポーネント
  • Vercel - ホスティング、CDN
  • GitHub Actions - ビルド環境

という技術を使っていくことになりました。

実装

次はいよいよ Hugo によるブログシステムを実装していきます。 オリジナルのテーマとサイトに必要な機能を作ります。

記事内の画像の表示

デフォルトで実装されている機能もあるので、サクサク進むのですが、 工夫が必要だったのが記事内の画像の表示です。

Markdown で画像を貼る場合は

![キャプション](パス)

と書きます。通常の Markdown プロセッサはこれを

<img src="パス" alt="キャプション" />

という HTML に変換します。今回は AMP を使うので、img タグではなくて amp-img を使う必要があります。さらに、amp-img の制約として、画像の幅と高さをタグの属性値で指定しなければなりません。これで CLS を防げるわけですね。結果的に以下のタグになる必要があります。

<amp-img
  alt="キャプション"
  src="パス"
  width="900"
  height="675"
  layout="responsive"
>
</amp-img>

これを HTML でベタ書きするのではなく、Markdown の記法そのままで書きたい。

ちょうどよく Hugo には以下の 2 つの機能がありました。

  • Markdown Render Hooks - 画像、リンクなど Markdown の描画機能をオーバーライドできる。
  • Image Proccesing - 画像をリソースとして扱うことで、リサイズやクロップを可能にする。

これらを使えば、わざわざ執筆者が画像のサイズを調べて HTML をベタ書きすることなく、 Markdown の記法で画像を貼るだけで理想のamp-imgタグを吐いてくれます。

さらには、リサイズの機能を使って、いくつかのサイズの画像を srcset で指定しました。 これで、ビューサイズによって画像の出し分けが出来ます。

こんな感じのテンプレートになりました。

<figure>
  <amp-img
    alt="{{ $.Text }}"
    width="{{ $img.Width }}"
    height="{{ $img.Height }}"
    srcset="
        {{ $small.RelPermalink }} 458w,
        {{ $medium.RelPermalink }} 726w,
        {{ $large.RelPermalink }} 1200w"
    src="{{ $small.RelPermalink }}"
    layout="responsive"
  ></amp-img>
</figure>

その他の機能

他に特徴的な機能として、

  • 記事ごとに執筆者表示。
  • ファイル名(cover.png)による OGP 画像の設定。
  • embedly によるリンク先情報の埋め込み。
  • Twitter の埋め込み。

などが実装されています。

ディレクトリ構造

最終的な Hugo のディレクトリ構成です。

.
├── archetypes    # hugo new した時のデフォルトテンプレートを入れる
├── assets        # CSS/SCSSなどのアセットファイル
├── config.toml   # 設定ファイル
└── content       # Markdown記事を入れる
   ├── about.md             # /aboutページ
   ├── authors              # /authorsページ
   │   └── yusukebe         # ユーザー名でディレクトリを作る
   │       └── _index.md    # 自己紹介ページ
   └── posts
        └── fastly-compute-slack-command # 記事ごとにディレクトリを作る
           ├── cover.png # 記事で使うOGPのカバー画像
           ├── index.md  # 記事のMarkdownファイル
           ├── ss01.png  # 記事内で参照する画像
           ├── ss02.png
           └── ss03.png
├── layouts      # レイアウト用のテンプレートファイルを入れる
├── public       # 生成されたHTML、アセットが入る
├── resources    # 生成された画像などが入る
└── static       # 静的ファイルを入れる
      └── images
          └── authors
             └── yusukebe.jpg # ユーザー名の画像が参照される

記事を書く時は content/posts/post-title/index.md を編集することになります。

ここまで来ると、Hugo のシステムはだいたい完成。あとはデザイナーからデザインをもらって適応するだけです。

執筆フロー

最後に執筆フローについて。これはまだ初めたばかりなので、変更されると思いますが、当初は以下のようなフローでいきます。 Building a personal blog with Hugo and Vercel を参考にしました。

preview ブランチに push すると、Vercel が例えば https://tech-blog-dqsk3omadff-travelbook.vercel.app/posts/fastly-compute-slack-command/ といっためちゃくな名前のホスト名で URL を発行してくれます。 この URL を渡すだけで本番前のプレビューができちゃいます。非エンジニアの人に見てもらう時に使えます。ちなみに、このページは ヘッダで noindex が設定されているので Google にインデックスされることはありません。便利ですね。

しばらくこのフローを試してみたいと思います。

(おまけ) Lighthouse スコア

ブログがほぼ出来上がった状態でプレビュー URL を Google PageSpeed Insights にかけてみました。 やった 97 点!目指せ 100 点!

まだ何も始まっていない

以上、どのようにこのテックブログを作ったか

  • 方針
  • 技術スタック
  • システムの実装
  • 執筆フロー

について紹介してきました。

強調したいのは、このブログはまだ始まったばかりで「何も検証されていない」ということです。偉そうに書いてきましたが、この仕組みが果たしてイケてるかどうか分かっていません。そのうち、検証した結果をお伝えできればいいと思います。

エンジニア募集中!

トラベルブックではエンジニアを募集中です。 イケてるブログ記事を書きたい方、イケてるブログシステムを作りたい方は一緒にやりましょう。 ブログに関わらず、興味を持った方は募集要項をチェックしてみてください。