こんにちは、フロントエンドチームの 谷(@high_g_engineer)です。
今週のフロントエンド定例の内容を記載します。
フロントエンド定例について、以前の記事(ランサーズのフロントエンドチームが取り組んでいること)でお伝えしたのですが、毎週金曜日に開催しており、実際の業務で取り組んでいることや気になった技術情報等をシェアしあう会になっています。
以下が今週の内容です。
Next.jsとは
Reactをベースとしたフルスタックフレームワークです。
フロントエンド界隈では説明不要なレベルで広く利用されているものです。
ReactとNext.jsの違い
Reactはクライアントレンダリングのみの為、html生成等を全てをブラウザ側で処理する事になり、小規模では効果を発揮しますが、大規模になったときに描画が遅くなったり、レイアウトシフトが発生したり、SEO対策が出来なかったり等のデメリットがあります。
Next.jsは、SG, SSR, ISR等の手段でプリレンダリングが出来る為、読み込み速度向上やSEO対策もでき、大規模でも耐えうる作りが可能です。
プリレンダリングについて
SG
- ビルド時に既にデータが埋め込まれた状態のhtml, css, jsを生成する手段です。
- ブログ、ドキュメント、EC商品紹介ページ等、データが動的でなくてもよく、更新頻度が高くないページで有効です。
- 出力された静的なファイルを配置すればよいので、どんなWebサーバでも利用可能です。
SSR
- リクエスト時にデータを埋め込んだhtmlをブラウザに返します。(一般的なバックエンドフレームワークの挙動です。)
- データが動的(プロフィール、タイムラインなど)で更新頻度が高く、リアルタイムなページで有効です。
ISR
- インクリメンタル静的再生成
- キャッシュ戦略を用いたSGの拡張的なものです。
- ユーザは、SGで生成された静的なページデータのCDNキャッシュデータを確認します。指定時間後にアクセスが合った場合、再度SGが実行され、キャッシュが置き換わる形になります。
ハイドレーション
プリレンダリングされたデータを読み込む際のクライアント側の挙動は、htmlが読み込まれた後、jsが読み込まれ、その後イベントなどが紐づく形になります。
これをハイドレーションと呼びます。
インスタントラーメンにお湯をかけて食べられる状態にするイメージです。
補足
Next.jsではページごとにSG, SSRが利用可能です。
公式の紹介としては、基本的なページはSG、動的なページはSSRというハイブリッドな利用を行います。
Next.jsの始め方
npx create-next-app プロジェクト名
色々聞かれるので、質問に答えきると環境構築が始まります。簡単!

ディレクトリ構成は以下の様になっています。

下記コマンドを実行することで、初期状態でホットロードが効く環境が立ち上がります。
yarn dev

SGについて
SGの手順
1.yarn buildでビルドエラーが無いか確認します。
2.src/api/を削除します。
3.next.config.jsを変更します。
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  trailingSlash: true,
}
module.exports = nextConfig4.next exportを実行します。
初期コマンドとしては無い為
・npx next exportとする
・exportコマンドをpackage.jsonに追加する
等の対応が必要です。
5.out/以下に静的なリソースが生成されます。

あとは、これをWebサーバに配置するだけです。
Vercel等であればこの辺りも自動化可能です。
データを埋め込む場合
getStaticPropsを利用します。
↓Next.js公式のコードを引用
// posts はビルド時に getStaticProps() によって生成されます。
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}
// この関数はサーバー側のビルド時に呼び出されます。
// クライアント側では呼び出されないので、
// 直接データベースクエリを実行できます。
export async function getStaticProps() {
  // posts を取得するために外部 API をコールします。
  // どんなデータ取得ライブラリでも使用できます。
  const res = await fetch('https://.../posts')
  const posts = await res.json()
  // { props: { posts } } を返すことで、Blog コンポーネントはビルド時に
  // `posts` を prop として受け取ります。
  return {
    props: {
      posts,
    },
  }
}
export default Blog
SSRについて
データを埋め込むコードを記述する場合、getServerSidePropsを利用します。
getStaticPropsとほぼ同じコードを記述することで実現可能です。
↓無理やり目にURLで値を動的に変更するロジックです。
import React from 'react'
import { GetServerSideProps } from 'next'
type NewsItem = {
  id: string
  title: string
  content: string
}
type Props = {
  news: NewsItem
}
const Page: React.FC<Props> = ({ news }) => {
  return (
    <div>
      <h1>{news.title}</h1>
      <p>{news.content}</p>
    </div>
  )
}
export const getServerSideProps: GetServerSideProps = async (context) => {
  const queryId = typeof context.query.id === 'string' ? context.query.id : ''
  const dummyList = [
    {
      id: '0',
      title: 'test0',
      content: 'texttext0',
    },
    {
      id: '1',
      title: 'test1',
      content: 'texttext1',
    },
    {
      id: '2',
      title: 'test2',
      content: 'texttext2',
    },
  ]
  return {
    props: {
      news: dummyList[+queryId] || {},
    },
  }
}
export default Page実運用のおはなし
実運用となった時にSSRが出来ること必須級な要件になり、SSRの為には、getServerSidePropsが実行できるSSRサーバ必要になってきます。
これは、Vercelなら何も考えなくても実現可能です。
(ただ、商用利用や企業での利用はお金がかかります…。)
- 最大 10 人のチームメンバー
- 詳細な請求書設定
- ビルドの並列化(1スロットにつき $50/月)
- ブランチごとのプレビューデプロイメント($100/月)
- 独自のパスワード保護($150/月)
現実問題、VercelではなくAmplifyなどの代替手段で実装する方向になってきます。
具体的なプラットフォーム
- AWS lambda + S3 + CloudFront
- CloudFunctions + Firebase Hosting
- AWS Amplify
- Netlify Functions
- etc…
参考:
https://hackmd.io/@euxn23/r1zO5zzpw
もはや、Next.jsの話というよりも、SSRを実行する為のより良いBaaS選定の話になってきます。
というところまでが今週の報告です。
ランサーズでは、フロントエンドエンジニアを随時募集しておりますので、まずはお話でもという方はご連絡くださいませ!
フロントエンドエンジニア(本社)の採用情報 | ランサーズ株式
前回の定例内容はこちらから確認可能ですのでご興味いただければ下記のリンクから閲覧いただければと思います。
