🐍

【2024年12月】Next.jsで新規アプリの構成と開発でのLLM活用

2024/12/13に公開

選定の方針

  • ログイン機能があるような、ユーザーが極端に多くないサービスを想定しています。
  • 開発効率の重視して、出来るだけWebアプリに集中できる構成を目指しています。
  • コスト理由で中断しないように、個人でも支払える費用感を意識しています。

EditorはCursorがおすすめ

開発用のエディタはCursorがおすすめです。

https://www.cursor.com/

  • LLMへの質問や修正を依頼する時に、修正対象と一緒に関連しそうなコードも送ってくれるので質問に対する回答の精度が高くなる (既存のコードに合わせた回答・修正をしてくれる)
  • コードをLLM側の学習に使わないようにしてくれる設定もあるのでセキュリティ的にも安心

(1) エディタ右上の歯車のマークをクリック

(2) Privacy Mode を enabled に変更する

より詳細な機能の解説はこちらの記事がわかりやすかったです。

https://zenn.dev/gamuprog/articles/53e7adee04b337

(僕は契約できていませんが、GitHub Copilotでもo1-previewやo1-miniなどの最新のモデルを使えるようになってきているので、今後またおすすめが変わるかもです)

開発時の検索はPerplexityがおすすめ

開発での検索はよりダイレクトに回答を得やすいので、Perplexityを活用しています。

https://www.perplexity.ai/

Google検索時のキーワードを入力するよりも、より文章に近い形でピンポイントに知りたいことを聞いてしまうのがおすすめです。

もちろん、間違った回答の可能性も一定あるんですが、引用情報が付与されているので、必要なドキュメントへ辿り着くコストも減らせます。

ページのモックを作る時のLLM活用

ページのモック作成はいろんな選択肢があって、色々試しています。

Vercelが作っているv0はプロトタイプを作るみたいな時に良いなと思っています。僕は以下の流れでプロトタイプを作ってブラッシュアップすることが多いです。

  1. Claudeで要件をできるだけ詳細にまとめた英語プロンプトを作成
  2. v0でプロトタイプ作成
  3. プロトタイプで気になった部分を細かく、Claudeに伝えて英語プロンプトを改善し、(2)へ

v0は出力がReact + shadcn/ui(Tailwind CSS)のコードを生成してくれるのでシームレスにコードにできるのが良いなと思っています。

https://v0.dev/

まだあまり試せてはいませんがBoltはよりアプリ全体のプロトタイピング+コーディングを進めてくれるみたいなのでこれから活用方法を模索したいと思っています。

https://bolt.new/

よりプロトタイピング重視の視点では、Figma AIも着実に進歩しているみたいです。作成後の手作業での調整を含めて考えるとこちらも十分に選択肢になる気がしています。

あと、純粋なコーディングの視点だとAIUIが安価で優秀なので、Figmaで作成したデザインをコーディングするときとかによく活用しています。

https://www.aiui.me/

今は最適解がまだ見えてないですが、自分のユースケースに合うものを模索していくのがおすすめです。

Next.jsライブラリ構成

メインで使っているライブラリです。Next.js + Vercelの開発体験が良すぎるので、できる限り活用して開発することを意識して作っています。

  • フレームワーク
  • メインで使うライブラリ
  • パッケージ管理
    • pnpm: yarnより早いパッケージマネージャー
  • 便利ライブラリ
    • knip: 不要な export 、依存関係のないファイルを削除

Style/CSS に関して

v0の出力で使われているTailwind CSS + shadcn/uiを使うようにしています。

https://ui.shadcn.com/

ベースのコンポーネントをディレクトリにコピーして、自由にカスタマイズできるところが気に入っています。

よく使うインフラ系サービス

  • Vercel: Gitにpushするだけでプレビュー・本番がデプロイできて便利です。
  • Firebase Auth&Firestore: Googleが提供する完全マネージドの認証とNoSQLサービス。
  • Cloudflare: ドメイン関連のサービスを中心に利用しています。
  • Sentry: 無料枠があり、予期せぬエラーの検知に便利。

ディレクトリ構成

Next.jsを使用してアプリを構築する際のディレクトリ構成について紹介します。最近作っているプロダクトで、appディレクトリ内でそこでだけ使う実装はできるだけそのディレクトリ内に設置するようにしています。

├─ app/
│  ├─ api/
│  ├─  ├─ hello/
│  ├─  ├─  └─ route.ts
│  └─ posts/
│     ├─ _components/
│     └─ page.tsx
│     └─ [postId]/
│         ├─ page.tsx
│         ├─ _components/
│         │  └─ postButton/
│         │     └─ index.tsx
│         ├─ _hooks/
│         │  ├─ useYYY.ts
│         │  └─ useYYY.test.ts
│         └─ _types.ts
├─ components/
│  ├─ elements/
│  │  └─ Button
│  │     └─ Button.tsx
│  └─ layouts/
│     └─ Header
│        └─ Header.tsx
├─ types/
├─ libs/
└─ utils/

/app

  • App Routerを使う場合はそのスコープ(feature)を小さく保つように実装しています
  • 特定の機能やドメイン専用のAPIアクセス、Hooks、コンポーネントなどを含みます
  • 影響範囲を限定してコードの読みやすさを重視してます (再利用性よりもスコープを小さくする方がフロントでは作りやすいと感じています)

/components

  • アプリケーション全体で共通して使用されるコンポーネントを格納します。
  • サブディレクトリには以下のようなものがあります。
    • elements/ 例:Button
    • layouts/ 例:Header

/libs

  • ライブラリ関連の設定などを格納します。

/utils

  • アプリ全体で共通して使用するユーティリティ関数を中心に格納

App Routerでfeaturesディレクトリを別で分けるべきか?

  • 前提として、できるだけ必要ないディレクトリは作らない方が良いと思います
    • 必要になったタイミングで追加していくのがおすすめです
  • 大切なのは「適切・継続的なリファクタリング」と考えています
    • Next.jsのアップデートや、より良いプラクティスがどんどん生まれていく
    • 生産性を上げるために必要なリファクタの時間を適切に確保していくのが大切と考えます

API: Route Handlers

appディレクトリ内で特定のルートに対してカスタムリクエストハンドラーを作成する機能です。

https://nextjs.org/docs/app/building-your-application/routing/route-handlers

  • appディレクトリ内のapp/api/hello/route.tsのように配置します
  • パラメータをNextRequestで受け取り、レスポンスで NextResponseを返す
import { NextResponse } from "next/server";

export async function GET(request: NextRequest) {
  return NextResponse.json({ message: "Hello, World!" });
}

https://www.pronextjs.dev/can-i-use-trpc-with-the-nextjs-app-router

ESlint

ESLint も詳しいわけでなく、少しずつ継ぎ足しながら、設定してきました。
もしより良い設定があればぜひ教えてください🙏

module.exports = {
  // ...
  extends: [
    "eslint:recommended",
    "next",
    "next/core-web-vitals",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:prettier/recommended",
    "plugin:redos/recommended",
  ],
  plugins: ["simple-import-sort", "import"],
  rules: {
    "@next/next/no-img-element": "error",
    "@next/next/no-page-custom-font": "error",
    "@typescript-eslint/ban-ts-comment": "off",
    "@typescript-eslint/ban-ts-ignore": "off",
    "@typescript-eslint/explicit-function-return-type": "off",
    "@typescript-eslint/no-floating-promises": "error",
    "@typescript-eslint/no-explicit-any": "off",
    curly: ["error"],
    eqeqeq: ["error", "always", { null: "ignore" }],
    "import/first": "error",
    "import/newline-after-import": "error",
    "import/no-duplicates": "error",
    "import/no-extraneous-dependencies": ["error"],
    "import/no-unresolved": "error",
    "no-console": "error",
    "no-debugger": "error",
    "react-hooks/exhaustive-deps": "warn",
    "react-hooks/rules-of-hooks": "error",
    "react/jsx-key": [
      "error",
      {
        checkFragmentShorthand: true,
        checkKeyMustBeforeSpread: true,
        warnOnDuplicates: true,
      },
    ],
    "react/jsx-no-bind": [
      "error",
      {
        allowArrowFunctions: true,
        allowBind: false,
        allowFunctions: false,
        ignoreDOMComponents: false,
        ignoreRefs: false,
      },
    ],
    "react/no-unknown-property": ["error", { ignore: ["custom-element"] }],
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off",
    "redos/no-vulnerable": "error",
    "simple-import-sort/exports": "error",
    "simple-import-sort/imports": "error",
    "sort-keys": [
      "error",
      "asc",
      { caseSensitive: true, minKeys: 2, natural: false },
    ],
  },
  // ...
};

Next.js周りの設定

Linkコンポーネントのhrefを型チェックするExperiemntalの設定です。

https://nextjs.org/docs/app/building-your-application/configuring/typescript#statically-typed-links

おすすめサービス

新規サービスはできるかぎりサービス開発に向き合った方が良いと思うので、外部サービスで使えるものは積極的に使っていきたいです。

リアルタイム性が高くなければ、料金やレイテンシを考えて、リクエスト時にAPI呼び出すよりはbuild時に呼び出して使うような形だと、無料枠で使いやすいと思います。

Airtable

テーブル設計ができてデータをAPI経由で取得できます。
エンジニアなどが使うマスタデータなどはこちらがおすすめです。

https://airtable.com/

Newt (Headless CMS)

Headless CMS で無料枠が充実しています。記事コンテンツなどのライターさんなどに記事を書いてもらう場合は、こちらがおすすめです。APIも使えてとても便利です。

https://www.newt.so/

Figma👉React&Tailwindへの変換

FigmaからReact/Tailwind CSS への変換はいくつかプラグインが出ています。こちらで生成したコードをベースにCursorでリクエストを出せば、かなりいい感じで実装してくれます。

https://www.figma.com/community/plugin/842128343887142055/figma-to-code-html-tailwind-flutter-swiftui

CodeRabbit

AIコードレビューツールです。GitHubのプルリクエストに対して、レビューコメントを書いてくれます。満足度的には40%くらいですが、たまにケアレスミスや実装ミスを指摘してくれます。特に一人で開発している場合は導入してみるのも良いかもです。

https://coderabbit.ai/ja/

アクセスが増えたらCloudflareを活用

アクセスが増えてきたらCloudflareをうまく活用していけないかを考えています。

Vercelのコストが増えてきたら

Vercelのコストが増加したり、レイテンシが問題になった場合は、Cloudflare Workersをプロキシとして利用する方法を試してみたいです。
Catnoseさんの記事にもあるように、静的ファイルをスルーしつつコストを抑えられそうです。

まずは検索流入を獲得するための静的ページに、Cloudflare WorkersとHonoを組み合わせたプロキシ利用を試してみたいと思っています。

https://zenn.dev/yusukebe/articles/647aa9ba8c1550

画像周りのアスセスが増えた場合

画像関連のアクセスが増加した場合は、Cloudflare R2とWorkersを利用することで、コストを抑えつつスケールできると考えています。

DB周りでボトルネックが発生した場合

DB周りでボトルネックが発生した場合は、Cloudflare WorkersHonoを組み合わせて、Read系や重い処理を部分的にキャッシュすることを検討しています。

https://hono.dev/

また、スケールして開発メンバーが増えてきた場合は、 Cloudflare Worker + GraphQLのアプローチで GraphQL のレイヤーで最適化を図っていくオプションも考えています。

https://zenn.dev/chimame/articles/3e7f0f0f7e783d

人数が増えたタイミングでリレーショナルデータベースの制約が価値を発揮するようになるので、Cloudflare D1Trusoを活用する方向に持っていきたいと思っています。

https://zenn.dev/shinryuzz/articles/cloudflare-d1-w-hono-n-drizzle

https://zenn.dev/ikumasudo/articles/df8ab4fb01038c

ブラウザを活用した処理を実装したい場合

ブラウザを活用した処理を実装したい場合はCloudflareのBrowser Renderingがおすすめです。

https://developers.cloudflare.com/browser-rendering/

内部的にはPuppeteerというGoogleが作っているChromium(ChromeのOSS版)を使ってそれを操作することができるライブラリがあり、そのPuppeteerのインスタンスを提供するサービスです。

参考にさせていただいた記事

https://zenn.dev/always_kakedash/scraps/4ea68ef01fc062

https://zenn.dev/yodaka/articles/eca2d4bf552aeb

https://zenn.dev/resistance_gowy/articles/91b4f62b9f48ec

https://zenn.dev/catnose99/articles/f8a90a1616dfb3

HOKUTO Tech Blog

Discussion