FrontEnd

Next.js 入門してみた

投稿日:

はじめに

Next.jsに入門して1週間で学んだことを記事にまとめます。

なぜNext.jsなのか?

今年は自分でも何か作ってみたいと思っているのですが、エンジニアとしてのテーマとして、経験したことのないフレームワークやプログラミング言語を取り入れたいと考えています。
とはいえ、領域から大きく外れすぎるとなかなか完成しないと思ったので、開発するものはWebアプリケーションとして、その中で新しい学びのある技術を選定する中で、フロントエンドにNext.jsを使いたいと思いました。
Reactでも良い気はしましたが、開発するとしたら、to C向けで、SNSの要素のあるサービスを開発したいと考えていて、その場合はSEOに強かったり、外部でシェアされる際にOGPが効くのもNext.js強みだと思ったため、とりあえずNext.jsを学んでみることにしました。

Next.jsとは何か

Next.jsは、ReactベースのWebフレームワークです。Reactを単体利用する場合との最大の違いは、ページをコンポーネントをSSRできるかどうかという点になります。
例えば、create-react-appで生成されたアプリケーションをビルドすると、生成されるHTMLはindex.htmlのみで、実際に表示されるDOMはすべてJavaScriptによって描画されます(SPA – Single Page APplication)。

かつてはRailsで構築されたWebアプリケーションのように、テンプレートエンジンがHTMLを生成するタイプのMPA(Multiple Page Application)が全盛の時代もありましたが、画面遷移するごとにページそのものが遷移するため、もっさり感がありました。
そこにSPAが登場することで、いちいちページ遷移することの煩わしさが解消されるようになりましたが、SPAはJavaScriptによってページが描画されるため、HTMLを静的解析するタイプのクローラに情報を提供することが難しいという問題がありました。

GoogleはSPAのページも読み取ってくれるようですが、TwitterやFacebookなどでOGPを設定するのは難しいようで、パブリックアクセスが必要となるニュースサイトやECサイトなどでは、導入が難しかったのではないかと思います。
そこで、Next.jsの強みは、ページが読み込まれたタイミングで、初期レンダリングされたHTMLをブラウザ側に返すことができる点です。これについて、Next.jsではいくつかのアプローチがあり、その概要を説明します。

Static Site Generation (SSG)

Next.jsのページは、デフォルトでビルド時にPre-renderされ、静的なHTMLファイルとして出力されます。レンダリングされる内容は、各ページのReactコンポーネントの初回レンダリングの内容になります。そのため、stateによって変化する内容については、含まれません。
これが一番シンプルなSSGなのですが、実際のコンテンツはAPIで取得するケースがほとんどではないかと思います。その場合は、ビルド時にAPIリクエストし、その内容をページのPropsの初期値として設定することができる getStaticProps を使用することで、外部リソースを含めてPre-renderすることができます。

さらに、Vercelが提供している useSWR というhookを組み合わせて、アクセス時にクライアント側で最新データをフェッチすることで、ビルド後も常に最新の状態を表示することができます。

Incremental Static Regeneration (ISR)

SSGによってPre-renderされるのは、Componentに埋め込んだ内容か、ビルド時にフェッチしたデータです。ビルド時より後に追加されたデータはPre-renderには含まれないため、SEOやOGPで不利であることは、CSRとほとんど変わりません。
そこで、ブラウザによりページアクセスがあった際に一旦は古いHTMLを返しつつ、前回のHTMLの生成から一定時間が経過している場合は、最新のデータを取得しなおした上でHTMLファイルを再生成することができるのが、ISRです。
これにより、最新のデータを含めるために再ビルドし直すことなく、SSGによるパフォーマンスやSEO・OGPなどの恩恵を受けることができます。ただし、ISRを使用している場合は、トリガーとなったページへのレスポンスや、HTML生成中のアクセスでは古いHTMLがレスポンスされるため、タイミングによっては整合性が取れなくなります。

Server Side Rendering (SSR)

ISRではタイミングによっては整合性が取れない場合がありますが、リクエスト毎に最新データを取得しつつ、サーバサイドでレンダリングすることでSEO・OGPに対応するには、どのようにすれば良いでしょうか。

そのような場合は、 getServerSideProps を使用します。この関数はページがリクエストされる毎にサーバサイドで実行され、この関数で返却されたPropsが渡された状態のコンポーネントがSSRされ、クライアントにレスポンスします。
あとは、SSGの時と同じように渡されたPropsをそのまま使ってコンポーネントを生成すれば、静的なHTMLとしてレスポンスされるため、SEO・OGPに対応することができます。

実際にNext.jsをセットアップ

Next.jsを特徴が分かってきたところで、実際にNext.jsを使ったアプリケーションを作ってみたいと思います。

create-next-app

create-next-app を使用すると、次のように対話形式でセットアップすることができます。

後半2つの質問はNext.js特有のものになります。

Would you like to use src/ directory with this project?

ここまで説明していなかったのですが、Next.jsではpagesディレクトリ配下の構成がそのままRoutingのパスとして解釈されます。デフォルトでは、pagesディレクトリはプロジェクトのルートに存在する必要があるのですが、これを src/pages に変更できるオプションです。
デフォルトではNoになっているため、私も今回はNoを選択しましたが、もしかしたらソースコードはsrcディレクトリの中にまとめてしまった方が、ルートがスッキリしてわかりやすくなるかもしれません。

Would you like to use experimental app/ directory with this project?

Next.js 13で追加されたapp directoryを使用するかどうかです。現時点ではベータ版の機能です。app directoryを使用しない、従来のNext.jsでは、コンポーネントの初回レンダリングの結果をHTMLとしてレスポンスし、その後はクライアント側でCSRが行われるという流れが1つのコンポーネントで完結できていました。
app directoryを使用した場合は、コンポーネントをServer SideとClient Sideに明確に分けるようになります。デフォルトではServer Sideで、Client Sideにする場合はファイルの先頭に use client とする必要があります。

Server Sideコンポーネントの場合は、これまで通りサーバサイドでレンダリングされ、これまで通りデータフェッチは可能ですが、stateやイベントハンドリングといったインタラクティブなことはできません。そのような部分はClient Sideとして実装する必要があるのですが、Client Sideコンポーネントはサーバ側ではレンダリングできません。

このような明確な分け方をすることにより、SSRした時のパフォーマンスが向上するとのことですが、実装時にはServer SideとClient Sideを上手く使い分ける必要がありそうです。
Next.jsのドキュメントに使い分けの例があるので、こちらを参考にした方が良さそうです。
https://beta.nextjs.org/docs/rendering/server-and-client-components

今回は、app directoryを使用しないことにしました。その理由は、MUIが未対応であるからです。
https://github.com/mui/material-ui/issues/34896

MUIほどの人気パッケージでさえ未対応なので、app directoryは正式版になるまで待っても遅くはないかなと思い、今回は使用しないことにしました。

nextの起動

yarn dev でnextアプリケーションを起動することができます。その他のコマンドは、以下がpacakge.jsonに定義されていました。

ちなみに、 dev で立ち上げた場合は、ページにアクセスされる毎に getStaticProps が呼び出されますが、 yarn build でプロダクション用のビルドをすると、ビルド時に取得したHTMLが使用されるようになります。

さいごに

次回も引き続き学んだ内容を記事にしていきたいと思います!

おすすめ書籍

TypeScriptとReact/Next.jsでつくる実践Webアプリケーション開発 Reactハンズオンラーニング 第2版 ―Webアプリケーション開発のベストプラクティス プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

blog-page_footer_336




blog-page_footer_336




-FrontEnd
-, ,

執筆者:

免責事項

このブログは、記事上部に記載のある投稿日時点の一般的な情報を提供するものであり、投資等の勧誘・法的・税務上の助言を提供するものではありません。仮想通貨の投資・損益計算は複雑であり、個々の取引状況や法律の変更によって異なる可能性があります。ブログに記載された情報は参考程度のものであり、特定の状況に基づいた行動の決定には専門家の助言を求めることをお勧めします。当ブログの情報に基づいた行動に関連して生じた損失やリスクについて、筆者は責任を負いかねます。最新の法律や税務情報を確認し、必要に応じて専門家に相談することをお勧めします。


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

Cordovaの実機デバッグでハマった話

1 はじめに2 Cordovaとは2.1 React Nativeとの違い3 Cordovaでモバイルアプリを作る3.1 Node.jsをインストール3.2 Cordovaのコマンドラインツールをイン ...

JQueryでformにinput要素を足していく

はじめに 最近個人的にディープラーニングの勉強をしているtonnyです。 ディープラーニングの勉強がてら、好きな麻雀に関するWebアプリを作成してみました。 今回はその作成の中で、今まであまりやってこ ...

icon

TypeScript初心者が押さえておくべき型システム

1 はじめに2 型アノテーション2.1 プリミティブ型2.2 リテラル型2.3 any2.4 nullとundefined2.5 ユニオン型2.6 交差型2.7 タプル型2.8 列挙型2.9 配列2. ...

正式版Vue.js 3.0のTeleportを触ってみる

1 はじめに1.1 Vue.js 3.0のプロジェクト作成方法1.2 Teleportとは2 基本形2.1 コード2.2 画面3 別のコンポーネントの入れ子にする場合3.1 コード3.2 画面4 同じ ...

Go言語

Go WebAssemblyでPromiseを使って非同期化してみた

1 はじめに2 Go WebAssemblyで非同期化のコード3 Promise化する4 おまけ5 さいごに6 おすすめ書籍 はじめに 先日WebAssemblyに入門して、実際に以下のチュートリアル ...

フォロー

blog-page_side_responsive

2023年1月
1234567
891011121314
15161718192021
22232425262728
293031  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。