先日、はてラボで「はてなアイコン」をリリースしました。普段はスマートフォンアプリを書いていることが多い
id:kouki_dan です。
サービスの紹介はリリース時のエントリを参照してください。このエントリでは技術的な裏側の紹介をしていきます!
Cloudflareスタックを試したかった
2年くらい前に、Cloudflare D1などが発表されて盛り上がっていた頃、Cloudflareを使ってなんか作りたいな〜と思っていました。はてなの社内には自由研究用のリソースとして、AWS, Google Cloudをはじめ、様々なクラウドサービスを特段の申請不要でエンジニアが自由に試せる環境が用意されています。もちろん費用は会社が出してくれて、常識的な範囲で使ってねということになっています。2年くらい前にCloudflareも追加してもらい、社内で自由にCloudflareスタックを試せる環境が整いました。
その頃に
id:onishi にCloudflareスタックでなんか作りたいよ〜。なんかちょうどいいアイデアありませんか?って話していたところ、出てきたのがはてなアイコンのアイデアです。そこで、リリースエントリで 「ブックマークしたURLを表示すると何故かリダイレクトされる という技術検証」と語られていた検証が始まります。
技術検証なので、Cloudflare Workerのブラウザエディタ上で、HTMLとJavaScriptを書いてあーでもない、こーでもないと、いろんなパターンを試していました。Faviconに関しては、単純にリダイレクトするくらいで動くかも?と思っていたのですが、単純にリダイレクトをするだけだと、ChromeのブックマークではFaviconがリダイレクト先のものになったりしていました。この辺りはブラウザの仕様次第なので、metaタグを使ったり、JavaScriprtを使ったりと、考えられることを色々と試していました。Cloudflareのブラウザエディタは、ワンクリックでデプロイでき、デプロイも異常に早く、本物のHTTPSのURLが発行されるので、検証が簡単に行えます。

このエディタ上で、技術検証を行い、当初実現したかった、「ブックマークしたURLを表示すると何故かリダイレクトされてFaviconも自由に設定できる」という挙動の実現方法を確立しました。コミット履歴を見ると、1年半前の2023年9月頃にやっていたようです。単一のサイトに対するはてなアイコンの100行弱のPoCがここで出来上がりました。
// index.js export default { async fetch( request: Request, env: Env, ctx: ExecutionContext ): Promise<Response> { if (request.url.endsWith("/manifest.json")) { const data = { short_name: "Hatena", name: "Hatena", display: "standalone", start_url: "/", icons: [ { src: "img.png", sizes: "1024x1024", type: "image/png", }, ], }; const json = JSON.stringify(data); return new Response(json, { headers: { "content-type": "application/json;charset=UTF-8", }, }); } return new Response( ` <html> <head> <title></title> <link rel="icon" href="img.png"/> <link rel="apple-touch-icon" href="img.png"/> <link rel="manifest" href="manifest.json"> </head> <style> body { display: grid; justify-items: center; align-items: center; width: 100%; height: 100%; } </style> <body> <div id="message"> ブックマークしてね! </div> <script> if (location.search === "?edit") { history.pushState({}, "", location.pathname); } else { var message = document.getElementById("message"); message.parentElement.removeChild(message); setTimeout(function() { document.getElementById("link").click(); }, 100); } </script> <a id="link" href="https://hatena.ne.jp" rel="noopener noreferrer"> <img src="img.png" width=300 height=300/> </a> </body> </html> `, { headers: { "content-type": "text/html;charset=UTF-8", }, } ); }, };
リリースを目指してHonoXで作り直す
PoCができた段階で、仕事が忙しかったりで、1年くらい放置してしまっていました。何がきっかけだったのかは忘れましたが、リリースを目指して作り直すことになりました。この時に選んだフレームワークは HonoXです。
HonoXはアルファステージですがCloudflareと組み合わせやすそうなことが魅力でした。もともと技術的にはCloudflareスタックを試したい、ということが起点にあったので、アルファステージということには目を瞑って、HonoXを選びました。ラボなんでね。
HonoXはCloudflareへのデプロイが簡単で早いのがお気に入りです。D1やR2など、他のCloudflareのプロダクトも簡単に利用を開始でき、Cloudflareで何か小さいものを作りたい、という時にはとてもオススメしたい選択肢だと思います。
Viteを初めて使ったので、この辺りで結構躓きましたが、ファイルベースのルーティングも、Honoの資産が使えることもとてもよく、全体的に開発体験は良かったです。
使った技術スタックは、以下の通りです。基本はHonoXの通りにPagesとFunctionsにデプロイ。データはD1に置き、画像はR2。セッション情報をKVに置くという使い方をしています。認証には、はてなのアカウントサーバーが持つ、OpenID Connectの機能を使用し、はてなIDを使えるようにしています。*1
- HonoX
- フレームワーク
- Cloudflare Pages (Functions)
- アセットとSSR
- Cloudflare D1
- ユーザー情報やアイコンの情報など
- Cloudflare R2
- アイコンの画像ファイル
- Cloudflare KV
- セッション情報
そしてリリースへ
HonoXとCloudflareをフル活用して開発してきたはてなアイコンが、機能的にはだいたい今の形まで出来上がってきました。デザイン以外は・・。デザインをどうしようかなぁとずっと
id:onishi と話していたところ、
id:akawakami がやってきて、CSSをどんどん書いて、今本番で出ているように素晴らしいデザインを当ててくれました。
リリースできそうな感じになってきていて、いつリリースするかを考えていると、今週末の1/31にははてなの半期末の納会で全社員が集まるタイミングがあるからそこでライブデプロイ&リリースしたらいいんじゃない?という話が浮かび上がってきました。
そうと決まると、
id:onishi は告知を書き、
id:akawakamiはデザインの最終調整を行い、
id:kouki_dan は環境を開発環境から本番環境へと移動したりして、当日を迎えます。ちょうどリリースされた1/31の17時くらいは、実ははてなでは全社納会が開催されていました。
新サービス「はてなアイコン」をはてラボでリリースしました https://t.co/TIgFDLgvrz
— はてラボ (@hatelabo) 2025年1月31日
無事ライブリリースを終え、今に至ります!
まとめ
はてなには自由研究用のリソースとしていろんなクラウドリソースをエンジニアが自由に試せる環境があります。はてなアイコンはそのCloudflareを使って色々実験していたら生まれたプロダクトです。 社内でCloudflareはあまり使われていなかったので、なんか欲しいな〜と思ってラボでリリースを目指していました。実際にリリースできて、HonoXを使ってCloudflareのプロダクト満載で簡単なWebアプリケーションを作るという例がはてなアイコンです。 はてなではいろんなエンジニアを募集しています!ぜひ興味がある方はカジュアル面談から始めましょう!
*1:現在ははてなIDのOpenID Connectの実装は社内のラボサービスなどに向けたもの。社員以外でも使えるようにする予定があるとかないとか・・?