ホーム自己紹介ブログ
NO.162
DATE2025. 11. 10

モダンな(?)フロントエンド技術セット

機能リクエスト投票サービス fequest (feature request の造語)を開発しています。
ユーザー向けと管理者向けの 2 つの Web アプリを構築中です。 開発中のコードは、以下のGitHubリポジトリで公開しています。

  • https://github.com/silverbirder/fequest

開発方針

これまでは慣れたツールセットでスピード重視の開発を行っていましたが、今回は久しぶりに「試してみたい技術」を積極的に取り入れています。

以前はツール導入に全力を注ぎすぎて、肝心のアプリが完成しないこともありました。
ですが今は、AI のサポートによってセットアップが驚くほど簡単になったので、コーヒー片手に気楽に新しい技術を試しています。

フォルダ構成

  • apps
    • user: ユーザー向け画面
    • admin: 管理者向け画面
  • packages
    • db: Drizzle で DB 管理
    • eslint-config: ESLint 設定
    • schema: Valibot スキーマ定義
    • storybook: Storybook 設定
    • typescript-config: TypeScript 設定
    • ui: 共通 UI コンポーネント
    • user-feature-xxx: ユーザー向けフィーチャー
    • admin-feature-xxx: 管理者向けフィーチャー
    • vitest-config: Vitest 設定

モノリポ構成を採用し、モノレポツールには turborepo を利用しています。
さらに、UI コンポーネントやフィーチャーコードを自動生成するために turborepo のコード生成機能 turbo gen を使用しました。

  • Generating code | Turborepo

アプリケーションフレームワーク

アプリケーションフレームワークは Next.js 16 を採用しています。
巨人の肩には、もう少し乗っておきたいところです。

  • Next.js 16 | Next.js

キャッシュコンポーネントはまだ使用していませんが、今後試してみたいと考えています。
「キャッシュ」という言葉には、どうしても少し抵抗があるんですよね……。

Next.js の設定には、以下の 2 点を追加しています。

  1. typedRoutes
    • Link の URL を型安全に扱える。
    • 動的ルーティングでは pathpida が必要になるかもしれません。
  2. reactCompiler
    • useMemo や useCallback を省略できる。
    • 安定版として使えるようになっているようです(?)。

また、PageProps インターフェースが自動生成され、params や searchParams に型安全にアクセスできるようになっています。

API 通信

API 通信には、慣れ親しんだ tRPC を採用しました。
本来は packages/trpc として切り出す予定でしたが、DB や認証との依存関係が複雑だったため、現在は apps 内に配置しています。

  • tRPC | tRPC

Lint / TypeScript 設定

eslint-config と typescript-config は、turborepo の create-turbo テンプレート由来で、そのまま利用しています。

  • Next.js | Turborepo

Schema

バリデーションスキーマには Valibot を採用しました。
普段は Zod を使っていますが、Valibot は後発のスキーマバリデーションライブラリなので、試しに導入してみました。
軽量だと言われていますが、実際のところは未確認です。

Storybook

Storybook v10 を使用し、フレームワークには @storybook/nextjs-vite を採用しています。
現時点では CSF 3 形式を継続使用中です。

v8.5 で Story にタグを付けてフィルタリングできる機能が追加され、v10 ではさらに「除外」もサポートされました。
これまでタグ機能をあまり意識していなかったので、今回知る良いきっかけになりました。

  • Storybook 10

Vitest と VRT

Vitest v4 を導入し、Storybook と連携したスナップショットテストを実行しています。
Story の play 関数にテストを書くのは少し抵抗があるため、現在は描画確認レベルのシンプルなテストにとどめています。

  • Vitest 4.0 is out! | Vitest

さらに、@storycap-testrun/browser を導入し、Storybook のテストランナー実行時に各 Story の VRT (Visual Regression Test) を自動実行するようにしました。
当初は Vitest や Storybook の公式機能で対応を試みましたが、うまく動作しなかったため、以下のアドオンを使わさせて貰いました。

  • @storycap-testrun/browser | Storybook integrations

vitest-config では Browser Mode ** の設定を行い、jsdom ではなく ** Playwright を利用した実 DOM テストを可能にしています。

  • Browser Mode | Guide | Vitest

これにより、await expect.element(el).toMatchScreenshot(); のような要素単位の VRT も実行できます。
現状では Story 単位の VRT で十分ですが、テストケースによっては使い分けも検討しています。

UI 構成

ui パッケージでは Tailwind CSS ** をデザイントークンとして使用し、 shadcn/ui** をベースに共通 UI コンポーネントを構築しています。

レイアウトコンポーネントは Chakra UI の思想を参考に自作しました。
以下のようなレイアウト系コンポーネントを用意しています。

  • Box
  • Center
  • Container
  • VStack
  • HStack
  • Flex
  • Grid

また、テキスト用の Text コンポーネントや、見出し用の Heading コンポーネントも定義しています。

CSS を書くのは好きなのですが、Tailwind を採用している以上、トークンベースで統一した方が保守性が高いため、スタイルはすべて Tailwind で管理しています。

このように、

デザイントークン → 共通コンポーネント/レイアウト → ドメインレベルのコンポーネント

という階層構造で UI を組み立てています。

デザイントークンをベースに、共通コンポーネントやレイアウトを使用しているため、基本的に tailwind の className はこのレイヤーまでで完結します。

ドメインレベルのコンポーネントでは、共通コンポーネントやレイアウトの variant を利用してスタイルを調整するため、直接 className を指定することは原則ありません。

全体としては、 Design Token-Based UI Architecture の考え方を意識し、 Option tokens → Decision tokens → Component tokens の三層構成でデザインを整理しています。

  • Design Token-Based UI Architecture
フロントエンド

-

コメント

0

読み込み中...

シェアする

フォローする

購読する

次のページ

AIに間違いを指摘したら「するどい指摘です!」と言われたときー

前のページ

Figma Make を使ってみた

関連する記事

タグ「フロントエンド」の記事

AIの書いたコードの手直しを減らすお作法

AI にコードを書かせた後、余計なコードを見つけて消す作業があります。 不毛なことなので、それらの作業を減らすためのお作法を紹介します。 未使用コードを消す 以下でも書きましたが、未使用コードの検査に knip を使うことが多いです。 ht

2026年02月25日

AI
フロントエンド
iframeの難しさ

最近、iframeを使っています。 クライアントサイドで埋め込む想定で、iframeを使おうとしています。 色々と苦労したことがあったので、書いて残しておこうと思います。 レスポンスヘッダー 前提として、ウェブアプリケーションをプロダクショ

2026年02月18日

フロントエンド
ブラウザ
SVGを書くと数学の知識が必要だった

紙を積んだイラストをSVGで書こうとしていました。 (当たり前ですが)図形を表現するためには数学の知識が必要で、学生の頃の記憶を思い出したので疲れました。 所感について、諸々書こうと思います。 成果物 実際に完成したのは、以下の画像ができま

2026年02月17日

フロントエンド
← ブログ一覧へ