カバー画像

note をやめて自前ブログ始めました

2022年2月3日 公開
プロフィール画像
大岡由佳@oukayuka
Mi Band 6 つけっぱ中。

ブログの更新が停まっていた理由

「りあクト!」シリーズ の版元である「くるみ割り書房」について、ブログ記事による情報発信を 2 年以上も休止していたのですが、このほど自前のブログシステムを構築したのでこちらにて再開いたします。

執筆・出版活動はずっと続けていたのになぜそんなに長い間、記事を発信していなかったか。理由のひとつは、それまで使っていた note にこれ以上コンテンツを置きたくなかったためです。ご存じの方も多いでしょうが、2020 年 8 月に note はいわゆる「IP アドレス漏洩事件」を起こしました。

OG Image

私もエンジニアですし、自分が原因で障害を起こしたこともあるので、このこと自体で note を責める気はありません。しかし問題は事後対応に見るこの会社の体質と運営の不誠実さにあります。
note のシステムは当時、フロントエンドを Nuxt.js、バックエンドを Ruby on Rails による Web API で構築していました。そして複数の市井のエンジニアの報告によると、その API ではユーザーの IP アドレスのみならずユーザー情報のテーブルを SELECT * FROM 〜 した項目をインターネットに向けて全公開していたとのことでした*1

Masahiko Sakakibara さんのツイート

まあそれもギリ許しましょう。しかし note の運営は記事ページの HTML ソースコードから IP アドレスが確認できたとしかいわず、しかも当初はそれによって個人特定はできないと論点ずらしのような弁明を繰り返しました。そして再三に渡るユーザーからの指摘にも関わらずそれ以外の漏洩情報について公式に触れることはなく、ただ再発防止の対策として「すべての記事ページの API レスポンスから現在のサービス運営に必須ではない項目を削除」したとしかこれまでのところ言及されていません。

情報漏洩の報告で、「どの範囲の情報」が漏れていたのかという事実を曖昧にするなどありえません。さらにそれが「いつから」「どれだけの期間」起こっていたかも明らかにしない。この経緯を見て、私の中で note の会社としての姿勢に対して不信感が芽生えました。

さらにその後も note はちょくちょく炎上事件を起こしており、体質を改める気はさらさらなさそうです。

OG Image

そういった会社が運営するサービスに自分のコンテンツを載せてその事業に加担する気になれず、その後の技術書典で新刊を出すときにも note にその告知記事を書くことはありませんでした。

実験的に Zenn で書籍の内容を一部公開してみたりもしてみましたが、サービスの性質上、あまり頻繁に宣伝的な記事を載せることははばかられます。

OG Image

けっきょく、その後長い間「くるみ割り書房」としての公式な情報発信は停まってしまっていました。

自前でブログシステム作っちゃいました

そういった利用サービスの運営元の事情に振り回されたりないためにも、自前でブログを持ちたいなと考え始めていたんですが、その作業量の多さが容易に予想できるためずっと二の足を踏んでいました。何かきっかけがほしいなと思っていたところに、Next.js が最近すごく伸びてるというニュースがたびたび耳に入るようになってきました。

東京 Node 学園祭 2016 のセッション でその存在を知ったのでおよそ 6 年前からウォッチしてはいたのですが、2020 年リリースのバージョン 10 で一気に注目を集め、この 2 年で npm の週間ダウンロード数が 30 万から 200 万へとなんと 6 倍以上に激増していました。
これは Vue.js 製の Next クローン的存在である Nuxt や、ライバルと目されていた同じ React 製の静的サイトジェネレータである Gatsby が同時期にほとんど伸びていないのと比べると驚異的です。

Next.js の npm trends グラフ

ここまでメジャーな存在になってくると、本まで書いている React エンジニアとしてノータッチなのはいかがなものかという危機感を抱くようになり、勉強がてらに Next.js でこのブログシステムを構築しようという気になった次第です。

ちなみに自前でブログを持つのは実に 10 年ぶりくらい。前回は Rails 製の CMS である Radiant というプロダクトを使ってテーマをカスタマイズした上で、Linode に一番安いインスタンスを借りて動かしていました。
今回は出来合いのプロダクトを使うのではなく自分でブログのシステムから作ることにしたわけですが、Next.js によるブログのサンプルコードは山ほど公開されているし、当初は軽く考えていました。しかしこの 10 年で一般的なブログができることや求められることの水準はかなり高くなっていたのです。

Markdown で書けることはもちろん、ただ URL を 1 行書いておくだけでそのドメインが Twitter なら本家で見るのと同じようにデコられたツイートの埋め込みに、YouTube なら動画が、Speaker Deck ならスライドがそのページで見られるのが普通。それ以外のドメインでもそのページの OGP 情報を盛り込んだリッチリンクなカードが表示されるのが普通。

また SEO でもコンテンツの価値のみにとどまらず、Google がページの品質評価に使っているという Web Vitals を始めとした基準にはサイトのパフォーマンスやアクセシビリティ、データ構造や PWA 対応といった多岐に渡る項目が対象に含まれています。

OG Image

もちろんこれらを抜きに昔ながらの最低限の機能のみを備えたブログにすることもできたのですが、やるからには完璧を目指してしまう性格なもので、けっきょく全部盛りに近いシステムになり、完成に見込んでいた予定期間を大きく過ぎてしまうことになりました。
(それでも Headless CMS 対応や i18n などがまだ未着手タスクとして残ってるのですが)

くるみ割り書房公式ブログを支える技術

このブログシステムがどういう技術を使って作られているか。まず基本のアプリケーションフレームワークとしては先述したように Next.js の最新バージョン 12 を使っています。さらに CSS フレームワークとしてこれも最近注目株の Tailwind CSS。Tailwind を使うことでデザイン構築のトライ&エラーのサイクルが圧倒的に早くなり、我ながらけっこうクオリティの高いサイトデザインになったんじゃないかと思ってます。

Markdown 対応のために使ったのが next-mdx-remote。さらにツイートや YouTube 動画などの埋め込みのための共通仕様である oEmbed に対応するために @remark-embedder/transformer-oembed という Remark プラグインを使いました。

あとリッチリンクなカードについては React や Next.js で汎用的に使えるよさそうなものがなかったので、自分で作ってしまいました。(これにすごく時間がかかった)

OG Image

OG Image

👆 のようなカードを表示するのに JSX なら、

<LinkCard url="https://klemiwary.com/" />
<LinkCard url="https://klemiwary.com/" size="large" />

と書けば表示されるライブラリを作り、ブログ記事内に表示するには Markdown で本文中に、

[くるみ割り書房](https://klemiwary.com/ 'linkcard')
[くるみ割り書房](https://klemiwary.com/ 'linkcard large')

と書くだけでいいようにしました。

ホスティングどうしてる

そしてこうやって作ったシステムをどこに置くかを考えたのですが、Next.js のアプリを一番手っ取り早く展開できる Vercel はフリーの Hobby プランは「Free for non-commercial sites」と明記されているため、同人サークルの情報発信には使えそうにありません。そのひとつ上の Pro プランは月額 20 ドルと、ブログを置くだけにはちょっと高い。

そこで Bejamas という Jamstack 開発者のための比較サイトを見たところ、Vercel のライバルとして挙げられていた Render というググラビリティのすこぶる低そうな名前のホスティングサービスがよさそうでした。ここなら無料プランで商用サイトとして Node アプリを稼働させても怒られそうじゃありません。

OG Image

アプリをデプロイしてみたところ、使い勝手もなかなかいい。お、これでいいじゃんとすっかり決めた気になっていたのですが、ちょっと作業した後にアクセスし直してみるとなかなかレスポンスが返ってこない。この挙動(コールドスタート)は Heroku で見たことがあります。おそらく Render でも無料プランはリソース節約のため、一定期間アクセスのないアプリは強制的にサーバプロセスを落とし、再度アクセスがあったときに改めて立ち上げ直しているのでしょう。

Vercel は無料プランでもずっと立ち上げたままでいてくれるのに。ひとつ上の月額 7 ドルの Starter プランにすることも考えましたが、けっきょくアプリを静的な SPA としてエクスポートし、同じく無料の Static Sites プランに置くことにしました。これならプロセスを落とされる心配がありません。

しかし Next.js は基本 Node アプリとして稼働させるのが第一選択肢であり、それをやめるといろいろ不都合が出てきます。静的な SPA としてエクスポートすると、開発環境で使えていた機能がポロポロ使えなくなります。そこでそれぞれ次のように解決しました。

  • 画像の最適化機能が使えなくなる
    next/image の image loader を imgix に移管。これも無料プラン内に収まりそう
  • pages/api に置いていた API が動かなくなる
    → 先述のリンクカードでリンク先のページ情報をリアルタイムに取得するのに使っていた。ページ生成時に getStaticProps() で本文中のリンクを抽出、リンク先をクロールして取得した情報を JSON ファイルに書き出す機能を追加
  • next.config.js や getStaticProps() 内でのリダイレクトができなくなる
    → 対象となるページコンポーネントを作って useEffect() 内で router.push() する
  • i18n ルーティング
    → そのうち使いたいと思ってた機能。どうするかは未定

この後の活動予定

公式サイトを持ってる技術同人サークルってかなりめずらしいんじゃないでしょうか。せっかくなので、これまでより積極的に情報発信していきたいと思っています。
それも含んだ今後の「くるみ割り書房」としての今後の活動予定(あくまで予定)をおしらせしておきます。

  • 「りあクト!」シリーズがこれまでどれくらい売れたか、収支報告の記事を書く
  • そろそろ正式バージョンが出そうな React 18 に対応した『りあクト! TypeScript で始めるつらくない React 開発』の第 4 版を出す
  • 先述のリッチリンクカードを OSS 化して公開する
    (Tailwind を使って作っているので、それを引きはがすのが大変そう)
  • 『りあクト! TypeScript で始めるつらくない React 開発』の英語版を出す
    (DeepL 先生、よろしくお願いします 🙇🏻‍♀️ )
  • このブログシステム構築の知見を生かして、「りあクト!」の Next.js 編を書く

それでは、今後ともこちらの公式ブログともども「くるみ割り書房」の書籍へのご愛顧をよろしくお願いします。


  1. Web アプリケーション開発にくわしくない方のために説明しておくと Web API は通常、非認証のアクセスではユーザーの情報は公開しても差し支えない限定的な項目しか返さないように設計します。
    しかし当時の note のシステムでは、とりあえず API からはデータベースのユーザー情報をまるっと全部返しておき、フロントエンド側で必要な情報をピックアップして表示するようになっていたものと思われます。そして開発時の何らかの確認のために、そこから IP アドレスを HTML にコメントで埋め込んでいたのでしょう。
    また記事についても、下書きの数など本人しか閲覧できないはずの情報が見られたという報告もあり、データの種類に関わらずそういう設計になっていたと推察されます。