2025-06-08

dubのソースコードを読んでみる

dubというURLを短縮し、トラッキングできるサービスがオープンソースで開発されており、Next.jsのApp routerを使って実装されているので、実装例を知りたいと思い、ソースコードを読んでみました。 https://github.com/dubinc/dub

セットアップ

https://dub.co/docs/local-development

tinybird

時系列のクリックイベントのデータを保存するために使用している https://www.tinybird.co/

tinybirdのバージョンが最近上がってドキュメントの通りにやってもclassicだから動かない tinybirdのclassicのdocker https://www.tinybird.co/docs/changelog/2025-03-14-march-week-two?utm_source=chatgpt.com

フロントエンドに確認したい箇所

認証周りの実装(currentUserの扱い方)

ログイン

実装方法が豊富なため、Providerパターンを使って共通の関数を使えるようにしているのだと思う。 useActionを使ってログインしている。

@upstash/ratelimitを使って、ログインのリクエストを制限している。

secondsの型がユニオン型の指定方法良いね

rest apiは用意してなくて、actionsでPrismaを使っている

サインアップ

サーバーでページを表示しても良いかのバリデーションを書けて、クライアントのページにはpage-client.tsxという名前を付けている

swrmutateを使ってリフェッチしている。 キャッシュのキーもrouteのパスもべた書きしているのが気になる。

認証のルートガードの実装方法

middlewareで認証していないユーザーがログインページにアクセスした場合に弾いている

next-safe-actionとは?

エラーハンドリングや認可処理の共通化を型安全に行えるようになるライブラリ

スケルトンの使い方

ローディングとスケルトンどちらも用意している。 スケルトンは普通にスタイリングして作っていた。

next-axiomとは?

サーバーレス時代のログ関数、パフォーマンス機能、web vitals、そしてプロダクトインサイト

バックエンドの確認したい箇所

Redisのキャッシュがどう使われているのか

一時データを保存するために使用されている。 キャッシュとしては特に使われてなさそう。

tinybirdの使い方

イベントトラッキングと分析のために使用されている。

テストの書き方

describe.sequentialを使ってテストが直列で実行されるようにしている。 直列で実行されるようにすることで、postで作成したデータをgetで使用するようにしている。 IntegrationHarnessで初期データを用意してそう。 HttpClientを使ってAPIのテストをしている。 返り値もテストしているけど、面白いのがランダムな値はexpect.any(String)のようにしている。

ロガーの設定方法

next-axiomというライブラリを使ってログを計測していそう。 middlewareでログを登録している。

api routerや、ページ遷移にめっちゃ時間がかかっている理由

レスポンスの型

ok: booleanが返ってきている エラーと、okがfalseの場合の違いって何なんだ? okがfalseの場合は基本的なエラーハンドリングをして、 catchのエラーになるのはネットワークレベルのエラーや予期せぬ例外をキャッチするために使っている

fetch使うとokが返ってくるんだ

エラーハンドリングの方法

errors.tsで実装している。 一つエラークラスを定義して、そこにcodeを指定することでエラーを分類している。

bottleneckの使い方

タスクスケジューラとレート制限ができるライブラリ。 過負荷を防ぐために使用されている。

全体の構成で確認したい箇所

どうやってpackagesに分割したものを使えるようにしているのか

pnpmのworkspaceを使っている。 tsupを使って、各パッケージをビルドしている。

メールの管理方法

nodemailerを使っている。textは普通に引数で渡している。

バグが本番に影響しないようにするための工夫(CIなど)

CI/CDでテストは実行しているが、APIのインテグレーションテストのみでフロントはテスト書かれていなそう。

感想

バックエンドはなく、サーバーレスで全部next.jsで実装されているのが面白い構成だなと感じた。 サーバーアクションの実装例を見ることができて参考になった。 ローディングが全てちゃんと実装されていたり、アニメーションがあったりとフロントエンドはとても作りこまれていると思った。 pnpmのworkspaceを使って、パッケージを分割しているのも良いなと思ったが、どうやって分けるかが結構経験がものをいうなと感じた。 ログや、クリックイベントをしっかりトラッキングしていた。 コンポーネントは基本的にProviderパターンを使って、共通の関数を使えるようにしているのが特徴的だなと思った。 今回初めてオープンソースのプロダクトを読んでみたのですが、知らないライブラリを知れたり、自分の実装の手数が増える感じがしてとても楽しかったです。