2020年末に入門するNext.js

この記事は、[Next.js Advent Calendar 2020](https://qiita.com/advent-calendar/2020/nextjs) の21日目の記事です。

# はじめに
この記事では、Next.jsを全く触ったことがない & kszkなエンジニアが、[公式チュートリアル](https://nextjs.org/learn/basics/create-nextjs-app)に則ってNext.js製ブログをデプロイするまでの様子をお届けします。

# 想定する読者
 - ふだんVue.js/Nuxt.jsで事足りていて、Next.jsのチュートリアルを時間をかけて読むモチベがない方
 - 毎月のように「来月はNextを勉強する」と言い続けて年末を迎えてしまった方（自分のこと）

（≒アドベントカレンダーを利用して自分のやるやる詐欺をついに実現しようという記事なので、同じような方のモチベになれば、くらいの軽い気持ちで書いています）


# さっそく入門していく
さっそく、[公式のチュートリアル](https://nextjs.org/learn/basics/create-nextjs-app)を始めていきます。
CLIでプロジェクト作成するところからNext.js製のブログを世に送り出すところまでガイドしてくれるようです。実践的👏

## 1. プロジェクトを作成する
[まずはコマンドでプロジェクトを生成します。](https://nextjs.org/learn/basics/create-nextjs-app/setup)

```bash
npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"
cd nextjs-blog
npm run dev
```
これで、 http://localhost:3000 に素敵なページが出来上がりました！
これから素敵なブログに仕立てていきます。

ちなみに

```json
"dependencies": {
    "next": "^10.0.0",
    "~その他省略~"
}
```
を使用しました。

## 2. ルーティング
[Next.jsでは`pages`ディレクトリ内の構造に従ってルーティングが行われます。](https://nextjs.org/learn/basics/navigate-between-pages/pages-in-nextjs)
ページ間の遷移は`Link`コンポーネントを用いるとのこと。`router-link`的な役割ですかね。

```react
import Link from 'next/link'

// 中略

<h1 className="title">
  Read{' '}
  <Link href="/posts/first-post">
    <a>this page!</a>
  </Link>
</h1>
```
これでトップページと記事詳細ページを行き来できるようになりました。
毎回importしたりLinkとaタグを両方書かなきゃいけないのがちょっとダルいかなぁ。

## 3. 静的ファイル（画像、CSS etc...）とメタデータ
静的ファイルは`public`ディレクトリに置くようです。いたって一般的。
HTMLのメタデータは`<Head>`コンポーネントに書いていく模様。

```
<Head>
    <title>First Post</title>
</Head>
```

次にCSSですが、ここでは[styled-jsx](https://github.com/vercel/styled-jsx)というvercel謹製ライブラリを使用して、[コンポーネントにスコープを限定した書き方とグローバルに適用される書き方が紹介されています](https://nextjs.org/learn/basics/assets-metadata-css/css-styling)。

このあたりは色々とやり方があると思うので、チュートリアル段階で深入りしなくても良さそうな気がします。
必要になったらググろうかな。
ということで、ガイドされるままにコピペしてブログのレイアウトを整えました。

## 4. Pre-renderingとData Fetching
ここがチュートリアルの肝だと感じました。
まずPre-renderingについてですが、[公式の図表](https://nextjs.org/learn/basics/data-fetching/pre-rendering)がとても分かりやすいです。
NextがコードをあらかじめHTMLに展開してくれるので、たとえブラウザのjsが無効になっていてもページが表示されます。
外野からすると、「Next.jsってSSRのフレームワークでしょ」というイメージだったので、いよいよ要点を解説するよ！という感じですね。

Pre-renderingには

 - `Static Generation` ... ビルド時にHTMLを生成する。
 - `Server-Side Rendering` ... リクエストごとにHTMLを生成する。

の2種類があり、ブログやドキュメントなど変更の少ないページはStatic Genして、それ以外はSSRしましょうとのこと。
Static Genする場合でも、ビルド時に必要なデータを取り込むことができて、
例えばブログの記事を外部から持ってくるには

```
export async function getStaticProps() {
  const allPostsData = getSortedPostsData()
  return {
    props: {
      allPostsData
    }
  }
}
```
とすれば解決する、と。
ページごとにStatic GenerationかSSRか選択できるようなので、ヘルプページとかはStatic Genしてサクッと返しましょう、という感じでしょうか。

クライアントサイドからデータを取りに行くならNext.jsチーム謹製ライブラリ[SWR](https://swr.vercel.app/)を使ってねとのこと。
キャッシュの面倒を見てくれたりするみたいですが、標準的なライブラリなんでしょうか。


## 5. ダイナミックルーティング
ブログページのスタイリング、生成方法も分かったところで、[次はダイナミックなルーティングについてです](https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data)。
要するに、ブログの各記事へのルーティングを `/posts/[id]` にしたいよ！というやつです。
具体的には

1. `/pages/posts/[id].js` を作成
2. `getStaticPaths()` で、可能なidのリストを返す
3. `getStaticProps({ params })` で、`params.id` をもとに必要なデータを取りに行く

で実現できました。シンプル！👏

記事を大量にGenしたい場合、ページネーションはどうするの？ と思いましたが、`getStaticPaths()`で`fallback: true`にすることで、[新規にリクエストされたページをリクエストのタイミングでGenできるみたいです](https://nextjs.org/docs/basic-features/data-fetching#when-is-fallback-true-useful)。
初回アクセスを踏んだ時にどれくらい待たされるか知りませんが、ブログとかヘルプとかなら許容範囲といったところでしょうか。

あとは、ver 9.5~ には [Incremental Static Regeneration](https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration) という機能もあるようです。
面白いですね！~~（適当）~~
ページ内の特定の箇所だけを更新したいときに使うんだ、みたいな話を聞いたことがあるような気がします。
いいね数とか、そういうやつですかね。Next仙人の方、教えて下さい。

どうやら`Next.js = SSRのフレームワーク`な時代は過ぎ去っていたようです。[^1]

## 6. vercelを使ってデプロイ
ここまでの作業でブログは完成したので、あとはデプロイするのみです！
コードをGitHubに置いて、[vercel](https://vercel.com/)(個人用の無料プラン)と連携させます。
特別な設定もいらず、「次へ」ボタンをぽちぽちしていくだけでデプロイされました🚀🚀
速い！👏
![スクリーンショット 2020-12-21 19.30.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906773/822fcd60-7174-8acb-3f0b-7d30634cded2.png)

しかも、GitHub上でプルリクを作ると、あら不思議
![スクリーンショット 2020-12-21 19.33.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906773/5d3570d6-10ba-5c72-d9f9-f6f2c272c7fe.png)
vercel botがプレビュー用のURLを貼り付けてくれます。
えらい👏天才👏一生ついていきます🙌

vercelはチームで活用するには有料プランを使うしかないみたいですが、個人開発には十分すぎる機能なんじゃないでしょうか。
ちなみに、vercelを使うとSSR部分が独立したサーバーレスファンクションになったり、CDNをつけてくれたり、いたれりつくせりのようです。（さすがに制限があるかも。ちゃんと見てない。）

# まとめ
Next.jsはSSRだけでなく、Static Generationでバシバシ高速化されたサイトを作る方向を向いているんだなぁという印象でした。
Next.js x vercel な開発は怠け者に優しいのもポイントが高いですね🥺👏
サクッとお試しで個人開発をするときは、この組み合わせでやってみようかなと思える便利さでした。

ちなみに、プロジェクト作成〜デプロイまでの時間は1h47mでした。
ドキュメントを丁寧に読みながらやったので、急げばお昼休み中に終えられるくらいのボリュームかもしれません。
2020年内のNext.js入門、まだ間に合います！


[^1]: そういえば「[Next.js 4年目の知見：SSRはもう古い、VercelにAPIサーバを置くな](https://qiita.com/jagaapple/items/faf125e28f8c2860269c)」という記事を流し読みしたことがありました。あとでちゃんと読み返そう。