🐙

【2024年1月】Next.js での新規アプリの構成 & Next.js ディレクトリ構成(features)

2024/01/12に公開

選定の方針

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

Next.js ライブラリ構成

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

Style/CSS に関して

Vercelがリリースしたv0をいいなと思って、v0の出力で使われているTailwind CSS + shadcn/uiを使うようにしています。(v0活用は検証中です)

https://v0.dev/

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

  • Vercel: Gitにpushするだけでプレビュー・本番がデプロイできて便利です。
  • Supabase: PostgreSQLを中心に、認証や画像ホスティングにも対応。
  • Cloudflare: ドメイン関連のサービスを中心に利用しています。
  • Sentry: 無料枠があり、予期せぬエラーの検知に便利。

アクセスが増えた場合の想定

アクセスが増えてきたら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

ディレクトリ構成

Next.jsを使用してアプリを構築する際のディレクトリ構成について紹介します。この構成はいくつかの記事や過去の実装を参考を元に作成しています。気になる点があれば、ぜひコメントでお知らせください🙇

├─ app/
├─ components/
│  ├─ elements/
│  │  └─ Button
│  │     └─ Button.tsx
│  └─ layouts/
│     └─ Header
│        └─ Header.tsx
├─ features/
│  └─ /post
│     ├─ api/
│          │    └─ getPost.ts
│     ├─ styles/
│     ├─ components/
│        ├─ Post.tsx
│        └─ Posts.tsx
│     ├─ hooks/
│        └─ usePost.ts
│     └─ types/
│        └─ index.ts
├─ hooks/
├─ styles/
├─ types/
├─ libs/
└─ utils/

/app

  • Next.js の App Router を使う場合に利用します。
  • ( Page Router を使う場合は /pages )

/components

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

/features

  • 特定の機能やドメイン専用のAPIアクセス方法、コンポーネントなどを含みます。
  • 関心のある特定の領域にフォーカスすることで、影響範囲を限定し、管理が容易になります。

/hooks

  • 共通的に使われる複数のリポジトリをまたぐ実装、ロジックなどを格納します。

/styles

  • スタイリングに関するファイルを格納します。

/types

  • 型定義を中心に格納します。

/libs

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

/utils

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

App Routerでfeaturesディレクトリいるのか?

(1/13追記)
はてブのコメント本当にありがとうございます。
featuresディレクトリがあった方が良いか、なくても良いのかについての意見を書かせてください。

  • 大前提として必要ないと思うディレクトリは作らないほうが良い
    • 必要性の感じないディレクトリは最初は作らずに、必要になったら追加で良い
  • 個人で運営中のサービスではfeaturesは追加しました。今の所あった方が良いとの感想です
    • プロジェクトの複雑性、Next.jsへのチームの理解度等々を踏まえて判断すると良い
  • 大切なのは「適切・継続的なリファクタリング」
    • Next.js のアップデートや、より良いプラクティスの共有でベスプラは変わっていく
    • 生産性を上げるために必要なリファクタの時間をチームで確保していくことが重要

App Router についてはこの辺りの記事がとてもわかりやすかったです!ありがとうございます🙌

https://zenn.dev/yamadadayo123/articles/6cb4f586de0183

https://zenn.dev/overflow_offers/articles/20231215-directory-structure

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 },
    ],
  },
  // ...
};

おすすめサービス

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

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

Airtable

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

https://airtable.com/

Newt (Headless CMS)

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

https://www.newt.so/

CodeRabbit

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

https://coderabbit.ai/ja/

Next.js周りの設定

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

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

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

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