【作成3日】Next.jsでブログサイトを個人開発しました！

# はじめに
今回から、前回までのviteのアプリとは異なり、Next.jsでの開発にチャレンジしました！
Next.js特有の設定や動作などに苦戦しながらも、今回はブログサイトを開発しましたので、アプリのご紹介と学びについて共有いたします！

# アプリの機能

### 概要
Qiita APIとMicroCMSのAPIを使って記事の内容とブログの内容を表示するサイト。

https://github.com/Kei-dev-1213/next-tech-blog

### 技術スタック
```
- 環境
Next.js: v14.2.11
vercel: 37.4.2

- 言語
typescript: 5.6.2

- ライブラリ
react: 18.2.0
react-dom: 18.2.0

- CSS
tailwindcss: 3.4.10
daisyui: 4.12.10

- Test
testing-library/jest-dom: 6.1.5
testing-library/react: 14.1.2
types/jest: 29.5.11
```

### 主な機能
#### トップ画面
Qiita APIとMicroCMSから取得した4記事をそれぞれ画面上に表示する。

![after1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832049/10f65b35-ff5b-945b-4fee-03709b87bfc4.gif)

#### Qiitaの記事表示
TOP画面上の「Posts On Qiita」の「もっと見る」ボタンを押下すると記事の全件を取得し、画面上に表示するページに遷移する。
また、記事のカードをクリックすると、別タブでクリックした記事に紐づくQiitaのページが表示される。

![after1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832049/958edf9f-7bc9-9bee-2367-dc2db06ddc76.gif)


#### ブログの記事表示
TOP画面上の「Posts On Blog」の「もっと見る」ボタンを押下すると投稿したブログの全件を取得し、画面上に表示するページに遷移する。
また、ブログ記事のカードをクリックすると、記事に紐づくブログの詳細ページが表示される。

![after1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832049/8ea189e5-122a-55cf-7c5f-4b7b76d011a5.gif)

# 開発を終えた感想
今回のアプリ開発を踏まえた感想・反省点について共有いたします！

- **Next.jsのフォルダ構成の難しさ**
Next.jsはappディレクトリ配下に各ソースを配置するのですが、
そのフォルダ構成をどのようにするかが悩みどころでしたが、開発を進める中で何度か調整しながら最終的には以下の形になりました。
NextjsのAppRouterのルールで、パスに紐づくフォルダ配下にpage.tsxを配置する、などの決まり切ったルールはそれに従えば良いので悩みはなかったのですが、`自由に決められる部分（特にcomponents配下）に関してはルールが無いのでそれが逆に難しかった`イメージです。
今回のように複雑でないアプリであればそれほどぐちゃぐちゃにはなりにくいですが、アプリの規模が大きくなればそれだけ複雑になりやすくなると思うので、自分なりに最適な構成を見つけたいと思います。
ググってみた感じ、やはりここに関しては他の人も同様に悩まれているみたいなので、次以降の開発ではより意識したいと思います！

```:フォルダ構成（APP配下）
App
├── __mocks__
│   └── intersectionObserverMock.ts
├── _components
│   ├── layout
│   │   ├── Footer.test.tsx
│   │   ├── Footer.tsx
│   │   ├── Header.test.tsx
│   │   └── Header.tsx
│   └── ui
│       ├── pages
│       │   ├── AllPostsOnBlog.test.tsx
│       │   ├── AllPostsOnBlog.tsx
│       │   ├── AllPostsOnQiita.test.tsx
│       │   ├── AllPostsOnQiita.tsx
│       │   ├── BlogDetail.test.tsx
│       │   ├── BlogDetail.tsx
│       │   ├── PostsOnBlog.test.tsx
│       │   ├── PostsOnBlog.tsx
│       │   ├── PostsOnQiita.test.tsx
│       │   └── PostsOnQiita.tsx
│       └── parts
│           ├── BackButton.tsx
│           ├── HorizontalCard.tsx
│           ├── MorePostsButton.tsx
│           ├── PostTitle.tsx
│           ├── VerticalCard.tsx
│           └── WhileInView.tsx
├── _constants
│   └── index.ts
├── _types
│   ├── blogArticleType.ts
│   └── qiitaArticleType.ts
├── _utils
│   ├── fonts.ts
│   └── index.ts
├── api
│   ├── blog
│   │   └── route.ts
│   ├── blogs
│   │   └── route.ts
│   └── qiita
│       └── route.ts
├── blogs
│   ├── [id]
│   │   └── page.tsx
│   └── page.tsx
├── individuals
│   └── page.tsx
├── globals.css
├── layout.tsx
├── loading.tsx
└── page.tsx
```

<details><summary>フォルダ構成（全体）</summary>

```

.
├── app
│   ├── __mocks__
│   │   └── intersectionObserverMock.ts
│   ├── _components
│   │   ├── layout
│   │   │   ├── Footer.test.tsx
│   │   │   ├── Footer.tsx
│   │   │   ├── Header.test.tsx
│   │   │   └── Header.tsx
│   │   └── ui
│   │       ├── pages
│   │       │   ├── AllPostsOnBlog.test.tsx
│   │       │   ├── AllPostsOnBlog.tsx
│   │       │   ├── AllPostsOnQiita.test.tsx
│   │       │   ├── AllPostsOnQiita.tsx
│   │       │   ├── BlogDetail.test.tsx
│   │       │   ├── BlogDetail.tsx
│   │       │   ├── PostsOnBlog.test.tsx
│   │       │   ├── PostsOnBlog.tsx
│   │       │   ├── PostsOnQiita.test.tsx
│   │       │   └── PostsOnQiita.tsx
│   │       └── parts
│   │           ├── BackButton.tsx
│   │           ├── HorizontalCard.tsx
│   │           ├── MorePostsButton.tsx
│   │           ├── PostTitle.tsx
│   │           ├── VerticalCard.tsx
│   │           └── WhileInView.tsx
│   ├── _constants
│   │   └── index.ts
│   ├── _types
│   │   ├── blogArticleType.ts
│   │   └── qiitaArticleType.ts
│   ├── _utils
│   │   ├── fonts.ts
│   │   └── index.ts
│   ├── api
│   │   ├── blog
│   │   │   └── route.ts
│   │   ├── blogs
│   │   │   └── route.ts
│   │   └── qiita
│   │       └── route.ts
│   ├── blogs
│   │   ├── [id]
│   │   │   └── page.tsx
│   │   └── page.tsx
│   ├── individuals
│   │   └── page.tsx
│   ├── globals.css
│   ├── layout.tsx
│   ├── loading.tsx
│   └── page.tsx
├── .env.local
├── bun.lockb
├── eslint.config.js
├── jest.config.ts
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── README.md
├── tailwind.config.ts
└── tsconfig.json

```

</details>

- **サーバーコンポーネントとクライアントコンポーネントの切り分け**
  Next.jsの大きな特徴の一つが、サーバーコンポーネントとクライアントコンポーネントの概念で、適切に使い分けるのは難しく感じました。
  サーバーコンポーネントは、データフェッチや静的なコンテンツの表示に適しており、今回のアプリではQiita APIやMicroCMSからのデータ取得を行う部分で活用しました。
  一方、ユーザーインタラクションが必要な部分や、アニメーションを使用する箇所ではクライアントコンポーネントを使用し、「もっと見る」ボタンの実装や記事カードのクリックイベント処理などを実装しました。
  通常のReactとは異なり、考える必要が増えたのは正直煩わしくも思いますが、しっかりこの使い分けをすることを今後の開発でも活かしていきたいと思います！

<br>

- **エラー解決までの時間が短くなった**
  早いもので、プログラミングコミュニティ『JISOU』に入ってからこの課題で6つ目となりましたが、この課題は3日で完成させることが出来ました。それは、開発において`エラーに引っかからなかったということではなく、エラー解決までの時間が圧倒的に短くなった`ことによって実現できたと思っています！
  というのも、これまでの開発経験を通じて以下のようなスキルが身についたからだと感じています。
  - 過去に遭遇した類似のエラーとその解決方法を記憶しており、素早く対処できるようになった
  - オンラインリソースや公式ドキュメントを効果的に活用する習慣が身についた
  - エラーの原因を論理的に推測し、効率的に解決策を探る能力が向上した

  特に3つ目の能力はこれまででかなり向上したと思います。というのも、初見のエラーに対しても、時間がかかったとしても2、3時間で解決させることが出来るようになったためです。この能力は、これまでの開発経験から、`この辺でエラーが起きてるんだろうな`というアタリがつけられるようになったからですね。個人的には、`プログラム開発で個人差が出るのはエラー解決までの時間`であり、この能力は自分で何かを作ることでしか身につかないと思っています（少なくとも教材を上からやっていて身につく能力ではないと思います）。
  JISOUの課題もいよいよ次でラストですが、今後も個人開発は続けていこうと思いました！


# おわりに
いかがだったでしょうか。
今回のNext.jsを使ったブログサイト開発を通じて、モダンなWebアプリケーション開発の奥深さを改めて実感しました。最初は戸惑うことも多かったですが、一つ一つの課題を乗り越えていくことで、新しい技術への適応力と問題解決能力が向上したと感じています。
この経験を活かし、今後はさらに複雑なアプリケーションの開発にチャレンジしていきたいと思います。同時に、学んだことを他の開発者と共有し、コミュニティに貢献していくことも目標としています。
これからもプログラミングの旅は続きますが、こうした経験の積み重ねが、より良いエンジニアへの成長につながると信じています！

## JISOUのメンバー募集中🔥
プログラミングコーチングJISOUではメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
気になる方はぜひHPからライン登録お願いします！👇

https://projisou.jp/