[WIP] T3 Stackで作ったWebシステムにおいて Type SafeなCLIツールを作成できるか?
動機
T3 Stackについて勉強中です。まだフワフワ。
バックエンド - フロントエンドで型定義を共有し、APIの静的型付けを実現する。
いまのところ T3 Stack最強だと思っているんですが、一つ疑問が。
「APIの汎用性はどこまで担保できる?」
大きな B to C 向け Webシステムは、SDKやらCLIの提供が一般的です。
IaaS、PaaS、SaaSと幅広く。
それによる利用促進の効果も期待できます。
これは REST APIによる恩恵の一つだと思います。
果たして T3 Stackを使ったWebシステムでも、それらの提供が可能なのか?
とそれらしいことを書きましたが、つまり「バック・フロント密結合すぎない?」って感覚を打破したいのです。*1
その他の動機「ブックマークマネージャ自炊したい欲」
ブックマークマネージャーとして buku を使っています。
CLIベースでブックマークを管理するプロダクト。
これ、シンプルかつ便利でコンセプトも良い。
ただ自分の積ん読グセがひどすぎるので、もっと自分を戒める機能が欲しいなぁと。
CLIで利用可なブックマークマネージャとしつつ、
- 複数デバイス (Windows / Mac / Android / iPhone etc)
- 複数ブラウザ (Chrome / Firefox / Edge etc)
これらからアクセスできる環境を作り、一元管理してしまいたい。*2
元はといえば、数万の単位でブックマークをしてしまう自分が全て悪いんですが、この積ん読グセは治ることはない。
注釈
*1 tRPCを利用するCLIが作れるか?のほうが正しいかもしれない。あと、gRPCを間にかませれば割と簡単に出来そうですね。
*2 buku自体は bukuserver というもので Web UI があるようです。少し前の記憶ですが Basic 認証しか使えなかったはず。。。
tRPCのドキュメントからすると、 Client側の Type AppRouter が切り分けられれば出来そう。
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from '../path/to/server/trpc'; // <- ここの切り分け
const client = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/trpc',
// You can pass any HTTP headers you wish here
async headers() {
return {
authorization: getAuthCookie(),
};
},
}),
],
});
割とさっくり出来るのかな。。。
Webpackをいじったりとかだとしんどそうだな
暫定解決策「フロント・バックを別RepoにしてLinkする」
ここに記述が。
別リポジトリとしてしまって、フロントエンドのRepoでバックエンドを npm install してLinkする。
Router の型定義をimportして使う形。
ただ、この解決策の場合、参照しているバックエンドのパッケージが最新でなければ、型定義の乖離が生まれることになります。
暫定。
最も理想的な形は
- バックエンド / フロントエンド / CLI の monorepo
- CLIから参照するのは型定義のみ(バックエンドのセキュリティ担保)
- 一回のBuildですべて Buildされる( CLIもそのまま配布するだけ)
なかなか厳しそうだ
いや、結合点は 型定義の import だけだから、実は全然難しくないんじゃないか?
ちなみに、ChatGPTさんは T3 Stackが何か知らないらしい。
ヒントを見つけた。
Create T3 Turbo
こちら、フロントエンドに React / React Native (Expo) を構成した monorepo で、これを基盤とすればもう殆ど何でもできる最強テンプレートです。
- └ packages ( ワークスペース )
- └ api (tRPCの実装)
- └ apps ( フロント実装 )
- └ nextjs ( for Web )
- └ expo ( for Mobile )
こんな構成なんですが、実装は上記の nextjs とか expo の構成をパクれば良さそうだった。
- ワークスペースで trpc定義を実装
- apps でフロント実装をして、trpc の型定義を見させる
ざっくり書くとこんな感じで、それほど難しくなかった。
ただ、Buildでどれだけセパレートできるかが課題で、まだフワフワしている部分があるので引き続き調査。