A Day in the Life

このウェブサイトの実装 2020年版

r7kamura さんkzys さん に倣って、このウェブサイトの実装を紹介してみる。

ホスティング

Google Firebase Hosting を使って静的ファイルを配信してる。一部動的な実装に関しては、Cloud Functions for Firebase を使っている。静的ファイル配信は今は Netlify や Surge など、基本無料で超簡単に配信ができて高速なものが多々出てるのだけど、Hosting に限らず Firebase の他のサービスとの連携が楽、という理由で Firebase Hosting を使っている。

また最近の仕事でのサーバサイドはほぼ Firebase 製品ですませていることもあって、Firebase でなんかやる、というのが技術的にもやりやすいから、というのもある。

なお画像はストレージをだいぶ食うため、はてなフォトライフにアップロードして使っている。はてなフォトライフは Google Photos のようにオフィシャルツールから取得した直リンクの画像が見れなくなる、というようなことは無いと信じている(が使えなくなったらそれはそれでどうにかする)。

静的ファイルでの配信について

個人サイトを運営している人たちで、現時点でも続けている人たちは、静的ファイルでのジェネレートしていた人たちが多い気がする。古くは blosxom なんかを使ってね。

理由は多分二つあって、1つ目は少なくとも昔の静的ファイルジェネレータは、データソースがツールに依存しない形式が多く、markdown / html などの記事ファイルを読み込んでウェブサイトの構造に加工して出力するためシンプルな作り。単純なWebサーバさえあればサイト運営が簡単に継続できる。そして単純なWebサーバというのはコストが安い。これが CMS / blog のシステムを使っているとシンプルさが失われ、動的な要素を持つとなんだかのプログラムを動かすことになりコストが高く、継続して動かし続けるのが大変になり、ふとしたなにかのタイミング(久しぶりにサーバをを乗り換えたら動かなくなった、とかね)で失われることがある。

2つ目は、構造がシンプルゆえに、静的サイトジェネレータの技術理解をきちんとしていたり、ジェネレータ自体を自分で実装していたりしているので、別のものに移行するときにすんなり以降ができる、というのもあるのだろう。これが複雑な CMS なんかを使っていると、export する仕組みがあるとは言え、それを別のところで動かそうとするとホネで、結局めんどくさくなって移行せずにネットの藻屑へと消えて無くなったりもする。すごく良い記事が消えて無くなるのは悲しい。

ドメイン

Google Domains を使っている。以前はバリュードメインを使っていた気がする。この secon.dev を買ったのは 2020 からで、昔から自分のドメインをちゃんと持って継続しておくべきだった、と後悔している。

ドメインというのは自分の存在を表現する、インターネット上では重要な名前空間で、それを継続しなかった・持たなかったのは残念でならない。独自ドメインは個人サイトを運営するなら取っておくべきだ。

なお日本ではメジャーな、お名前.comやバリュードメインなんかは、1年目のドメイン代だけ表示して、2年目以降の値段は表示されず、1年目の値段提示だけで安価に買わせようとしていて、それに気づくのは次のドメイン更新時、みたいな悪徳業者な感じで、本当に良くないと思っている。住宅の例えをするなら、賃貸物件に住みだしたら一年目より二年目のほうが何倍も高い請求が来て、かつそこに住みだしてしまったので引っ越しが大変(レジストラ移管は面倒なのだ)、みたいなことになるので、ドメインを購入する人は二年目以降の価格もきちんと調べたほうが良い。

ビルド

静的サイトジェネレータには Next.js を使って実装した。この選定としては、一つは TypeScript で書きたかったこと、一つはフロントエンドの実装に React を使いたかったことが挙げられる。

Gatsby JS

同じように TypeScript で書け、React が使える静的サイトジェネレータとしては GatsbyJS もある。Gatsby はよく出来ていて、すべてのソースを一度 GraphQL に集約し、それを元に出力するファイルを作る。つまり GraphQL を使う、以外は自由で、そのためデータソースを GraphQL に入れるためのプラグインも山ほどあるし、そのデータをどう加工して出力するか、というプラグインも山ほどある。

他にも、例えば画像を自動でリサイズしてくれる、サイトマップを出力する、Google Analytics もいれる、などもプラグインを使うだけのプラガブルな仕組みが提供されている。

そのため、入力ソースはファイル形式でもSQLでもリモートソースでも何でもよくて、出力形式も markdown だろうが MDX だろうがプレーンな HTML だろうが何にでも加工がしやすい(ふんだんにプラグインがある)。もちろん例えば Algolia で検索したい場合も、アウトプット先の一つを Algolia にしてしまえばそれだけで簡単に全文検索ができるようになる。

なんで Next.js を使ってるのか

これだけ見ると、GatsbyJS はとても良く出来ていて、選定理由として選ばない理由はない感じがするのだけど、実際のところ WordPress のようなかおりがするのだ。山程プラグインはあれど、TypeScript で書かれているものも少ないし、なによりプラグインにテストが書かれているものが少ない。

UI に関するテストが書きにくい、というのはさておき、ユニットテストが書きやすそうなものや、データソース関連はテストが書かれていてほしいものだけど、そのへんもあまり書かれていないのを見ると、技術的な危うささを感じる。

もちろん、その分簡単にプラグイン作成に参入ができ、エコシステムとコミュニティが広がった、というのもあるのだろうけどね。

Next.js は Gatsby に比べるとだいぶ質実剛健な作りになっていて、Gatsby にはある「超簡単にいろんな機能を持ったサイトが作れる、すげー!」という華やかさは無いのだけど、安心して実装を進めることができる。長い目で見ると、その安心感があったほうが良い、と判断した。

記事の書き方

記事は、はてなブログで書いていたものは、はてなブログの export 形式である Movable Type 形式のファイルを mt-parserで読み込み、静的ファイルを出力しているいる。はてなブログの記事は、blogsync でファイル + 記事ごとの markdown として取得できるのだけど、その場合は markdown 上にかかれているはてな独自記法、たとえば [f:id:secondlife:xxxx] などが展開されないため、それらすべてが HTML に展開されている Movable Type 形式にしている。

新しく書いている記事は、VSCode + vscode-memo-life-for-you で書いて、Markdown Preview Enhanced でざっくりと確認している。書かれた記事の markdown ファイルは Dropbox 上で同期している。

ビルドするタイミングは、Dropbox で同期された記事ファイルの中から、Draft では無い記事の mtime を見て、以前のビルド時よりも新しいものがあればそれをトリガーにビルド、というのを Vultr 上の VPS にやらせている。

git に commit して push する仕組みだと、能動的な動作を必要としてしまい、もうちょっと雑にやりたかったので、Dropbox でのファイル同期にしている。

記事のフォーマットについて

また、記事のフォーマットは markdown + HTML で書いている。markdown は markup ではなく markdown という名前からも、HTML のようになにかテキストにマークアップ情報をもたせることを極力避けているため、よくも悪くも表現の幅が狭い。

とりわけこのサイトで問題になるのは、写真を貼り付けたときに意図したレイアウトにしにくいことがあって、その部分は HTML で書いている。

それを解消するために、markdown の中に JSX を書ける mdx などのアプローチや、markdown の記述順序によって HTML の出力を変えたり、独自の記法(はてなブログとか)を用いる方法あるが、今の所 HTML を貼り付ける形式にしている。

デザイン

デザイン、というか CSS フレームワークには Bluma を使って SCSS で書いている。flexbox が使える今、あえて CSS フレームワークを使う必要はないのかもしれないけど、昔使ったことがあって書き方をざっくり覚えていたこと、ちょっとしたデザイン(input や textarea とかね)をいい感じに当てれること、spaceing-heleprs が便利だったり、記事本文をだいたいいい感じにレイアウトする content が便利だったりで使っている。