小規模開発のフロントエンド技術選定
こんにちは。
Spacemarketのエンジニアの8zkです。
クリスマスツリーを買えないままクリスマスを過ごしました。寂しい。来年こそは買えるよう頑張ります!
前提
今回作成したアプリケーションは下記の通りです。
- 9画面ほどの小規模開発
- フォーム
- 検索
- ユーザー情報 etc...
- 技術選定を行なうタイミングがBEの技術選定の前(プロジェクトに入るタイミングがフロントエンドの方が早かった)
- 追加開発を行う想定
採用ライブラリ
採用したライブラリはこちらです。
{
"dependencies": {
"@chakra-ui/icons": "^2.1.1",
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@hookform/resolvers": "^3.6.0",
"axios": "^1.7.2",
"dayjs": "^1.11.11",
"framer-motion": "^11.2.11",
"humps": "^2.0.1",
"next": "14.2.3",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.51.5",
"swr": "^2.2.5",
"zod": "^3.23.8"
},
"devDependencies": {
"@babel/preset-react": "^7.24.6",
"@chakra-ui/cli": "^2.4.1",
"@chakra-ui/styled-system": "^2.9.2",
"@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
"@types/humps": "^2.0.6",
"@types/jest": "^29.5.12",
"@types/lodash.debounce": "^4.0.9",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.3",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.3.0",
"typescript": "^5"
},
}
Axios
AxiosもしくはFetch APIの2択になるかと思いますが、Axiosの方が処理が簡単に書けるのと、エラーハンドリングの容易さやインターセプターが使えることのメリットを考えてAxiosを選びました。
REST API × SWR
REST APIはBEの技術選定前にフロントエンドを決めることになったため、その時点ではGraphQLが使えるかわかりませんでした。
なのでGraphQLとRESTを比較してどちらかを決めたというよりBEがどういった技術でも採用可能なREST APIを採用しました。
また、キャッシュ機構を持っているため不要なリクエストを防ぐことができるといったメリットが多く採用しました。
SWRについての学びはこちらのブログにまとめているので覗いていただけると嬉しいです!
Next.js
SSRもSSGも使っていませんが、昨今のWeb開発のデファクトスタンダードになっており、create-next-app
を使うことで簡単にアプリケーションを構築できることなどが採用理由です。
React Hook Form × Zod
フォーム操作とバリデーション管理のライブラリではReact Hook Form と Zod を導入しました。
選定理由はダウンロード数・Star数が多く、軽量であることなどが挙げられますが、一番の決め手は他のプロジェクトで使っておりチームメンバーが学習コストなく触れることでした。
React Hook FormとZodについての学びはこちらのブログにまとめているので覗いていただけると喜びます!
Chakra UI
JSXの中にスタイルを書くことができ、TypeScriptの型を活かすことができます。
こちらも他のプロジェクトで使っていて学習コストがなく使えることが理由で採用しました。
Jest
JestはJavaScriptのテスティングフレームワークです。正直に言えば、選定に絶対的な理由はなく、社内の他のプロジェクトでも多く採用実績があったため採用した次第です。
機会があれば他のテスティングライブラリをちゃんと比較してみたいと思います。
ディレクトリ構成
ディレクトリ構成はfeaturesディレクトリを採用しました。
大体のロジックがfeaturesディレクトリ内に集約しています。
また、featuresの中は特定のドメインに紐づく処理をdomains、ページに紐づく処理をroutesに置きます。
public
├ images
src
├ app
│ ├ page.tsx
│ ├ layout.tsx
│ └ users
│ ├ page.tsx
│ └ layout.tsx
├ constants
└ features
│ ├ domains
│ │ └ auth
│ │ │ └ components
│ │ │ └ hooks
│ └ routes
│ └ Home
│ ├ components
│ ├ hooks
│ └ index.tsx
├ helpers
└ hooks
├ api
│ └ useApi.ts
└ useGetWindowSize.ts
appディレクトリ
ルーティングに関するページのコンポーネントを格納。
app
ディレクトリをfatにしないためにroutes
のコンポーネントを読み込むだけです。
import { Home } from '@/routes/Home';
export default function HomePage() {
return <Home />;
}
constantsディレクトリ
プロジェクト全体で使う定数の定義を格納。
都道府県の定義などを置きました。
export const PREFECTURES = [
'北海道',
'青森県',
'岩手県',
'宮城県',
'秋田県',
...
]
features/domainsディレクトリ
特定のドメインに紐づく処理を格納。
例えば認証周りやユーザー情報など特定のドメインに紐づく情報など共通で使われる処理を置きます。
domainsの中でもcomponents
、constants
、hooks
などディレクトリを分けることによってわかりやすくなります。
features
├ domains
└ auth
├ components
├ constants
└ hooks
features/routesディレクトリ
appと同じページ単位のディレクトリを作成し、そのページだけで使うcomponents
やhooks
などを格納。
features/domainsディレクトリと同様にcomponents
、constants
、hooks
などディレクトリを分けることによってわかりやすくなります。
helpersディレクトリ
アプリケーション全体で使う共通の関数を格納。
例えばlocalStorage
やライブラリの初期値を設定する処理などを置きます。
hooksディレクトリ
アプリケーション全体で使う汎用的なReact Hooksのコードを格納。
例えば画面のサイズを取得するhooksや、apiをcallするためのhooksなどを置きます。
まとめ
小規模開発ゆえに採用技術はそれほど多くはありませんでした。
しかし、リリースされて実際に使ってくれるユーザーがいるプロダクトのアプリケーションを環境構築したのは初めてで本当に楽しかったです。
この機会をくれた会社には感謝しています!(ごまをすってるわけではありません笑)
さいごに
スペースマーケットでは、一緒にサービスを成長させていく仲間を探しています。
話を聞いてみたい、ちょっとだけ興味がある、などでも大歓迎です!
ご興味ありましたら是非ご連絡ください!
スペースを簡単に貸し借りできるサービス「スペースマーケット」のエンジニアによる公式ブログです。 弊社採用技術スタックはこちら -> whatweuse.dev/company/spacemarket
Discussion