Chapter 03

Next.jsで静的なサイトを作ってみよう

Hidetaka Okamoto(Stripe)
Hidetaka Okamoto(Stripe)
2022.04.19に更新

ここからは、Next.jsでのサイト構築方法について簡単に学んでいきましょう。

まずは、最もシンプルな静的サイトを作ってみます。

静的サイトとは?

通常、WordPressやRuby on Railsなどで構築されたWebサイト・アプリケーターを公開するには、
PHPやRuby / Node.jsなどのプログラムをサーバー側で実行する環境が必要です。
サーバー側でプログラムを実行し、HTMLやAPIのレスポンスを必要に応じて動的に生成することができます。

静的サイトの場合、このサーバー側のプログラムで処理を行わず、「事前に生成したHTML/JavaScript/Image/CSSファイル」を配信します。
これによって、公開するサーバー・サービスにかかる負荷を減らすことや、コストダウンなどが期待できます。

静的サイトで使えない機能を削除する

Next.jsで静的サイトを作るには、サーバー側で実行する必要のあるコード・ファイルを削除する必要があります。

pages/index.jsからnext/imageを取り除く

create-next-appを利用した場合、サーバー側で画像の最適化を行う機能がpages/index.jsに追加されています。

pages/index.jsを開き、まずimport Image from 'next/image'を削除しましょう。

import Head from 'next/head'
- import Image from 'next/image'
import styles from '../styles/Home.module.css'

そして、ファイル下部にある以下のコードも削除します。

      <footer className={styles.footer}>
        <a
          href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
          target="_blank"
          rel="noopener noreferrer"
        >
          Powered by{' '}
          <span className={styles.logo}>
            <Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
          </span>
        </a>
      </footer>

削除後のpages/index.js

import Head from 'next/head'
import styles from '../styles/Home.module.css'

export default function Home() {
  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <h1 className={styles.title}>
          Welcome to <a href="https://nextjs.org">Next.js!</a>
        </h1>

        <p className={styles.description}>
          Get started by editing{' '}
          <code className={styles.code}>pages/index.js</code>
        </p>

        <div className={styles.grid}>
          <a href="https://nextjs.org/docs" className={styles.card}>
            <h2>Documentation &rarr;</h2>
            <p>Find in-depth information about Next.js features and API.</p>
          </a>

          <a href="https://nextjs.org/learn" className={styles.card}>
            <h2>Learn &rarr;</h2>
            <p>Learn about Next.js in an interactive course with quizzes!</p>
          </a>

          <a
            href="https://github.com/vercel/next.js/tree/canary/examples"
            className={styles.card}
          >
            <h2>Examples &rarr;</h2>
            <p>Discover and deploy boilerplate example Next.js projects.</p>
          </a>

          <a
            href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
            className={styles.card}
          >
            <h2>Deploy &rarr;</h2>
            <p>
              Instantly deploy your Next.js site to a public URL with Vercel.
            </p>
          </a>
        </div>
      </main>
    </div>
  )
}

pages/ディレクトリで、新しいページを追加しよう

静的化の準備ができたので、まずは新しいページを追加してみましょう。

Next.jsでは、pages/ディレクトリにファイルを追加すると、そのファイル名でページが生成されます。

pages/hello-world.jsxを作成し、以下のコードを入力して保存しましょう。

export default function HelloWorld() {
    return (
        <div>
            <h1>Hello World</h1>
        </div>
    )
}

http://localhost:3000/hello-world にアクセスしてみましょう。
npm run devを停止した方は、再度実行します)

Hello Worldと表示されたページが出れば、ページの作成に成功です。

next/headでページタイトルなどのSEOをお手軽に

検索やSNSでのシェアを期待するには、ページのタイトルや説明文などをheadタグ内に設定する必要があります。

Next.jsの場合、next/headライブラリを利用して設定ができます。

pages/hello-world.jsxを以下のように変更しましょう。

+import Head from 'next/head'
export default function HelloWorld() {
    return (
        <div>
+            <Head>
+                <title>Hello World</title>
+                <meta name="description" content="検索エンジン用の説明文" />
+            </Head>
            <h1>Hello World</h1>
        </div>
    )
}

ファイルを保存すると、ブラウザのタブにtitleタグの内容が表示されます。

このように、next/headHeadコンポーネントを利用することで、ページ毎に個別のtitleやmeta情報を追加できます。

pages/_app.jsで共通のレイアウトを設定しよう

TailwindやBootstrapなどのUIフレームワークを利用したい場合や、Stripe・Zendeskなどのライブラリを複数のページで利用したい場合、ページ毎にimportする設定を書くのは効率的ではありません。

全てのページで利用するコンポーネントやライブラリは、pages/_app.jsにまとめて実装できます。

React-Bootstrapライブラリを利用して、ヘッダーを全ページで表示させてみましょう。

Bootstrapをインストールしよう

まず、npm install react-bootstrap@2 bootstrap@5でライブラリをインストールしましょう。

※このワークショップでは、Bootstrap version 5.xをサポートしています。そのため、@でバージョンを固定したインストールを行います。

npm install react-bootstrap@2 bootstrap@5
+ bootstrap@5.1.3
+ react-bootstrap@2.2.3
updated 7 packages and audited 256 packages in 12.176s

Bootstrapでヘッダーを追加しよう

pages/_app.jsを開き、以下のように編集しましょう。

import '../styles/globals.css'
import 'bootstrap/dist/css/bootstrap.min.css'
import { Navbar, Container } from 'react-bootstrap'

function MyApp({ Component, pageProps }) {
  return (
    <>
      <Navbar bg="dark" variant="dark">
        <Container>
          <Navbar.Brand href="#home">
            Hello EC
          </Navbar.Brand>
        </Container>
      </Navbar>
      <Component {...pageProps} />
    </>
  )
}

export default MyApp

ファイルを保存すると、 http://localhost:3000/hello-world にも http://localhost:3000/ にも黒いヘッダーが表示されます。


http://localhost:3000/hello-world


http://localhost:3000/

pages/_app.jsの注意点

pages/_app.jsでは、<Component {...pageProps} />を必ず含める必要があることに注意しましょう。

このコンポーネントを消すと、pages/内の各ファイルで指定したページの内容が表示されなくなります。

npx next exportでサイトを静的化しよう

ある程度Next.jsを触ったところで、いよいよサイトを静的化してみましょう。

Next.jsでは、まずnpx next buildで作成したアプリをビルドする必要があります。

コマンドを実行すると、以下のようにビルドしたページやファイルの情報が表示されます。

npx next build

info  - Checking validity of types  
info  - Creating an optimized production build  
info  - Compiled successfully
info  - Collecting page data  
info  - Generating static pages (4/4)
info  - Finalizing page optimization  

Page                                       Size     First Load JS
┌ ○ /                                      962 B          84.5 kB
├   └ css/149b18973e5508c7.css             655 B
├   /_app                                  0 B            83.6 kB
├ ○ /404                                   192 B          83.8 kB
├ λ /api/hello                             0 B            83.6 kB
└ ○ /hello-world                           398 B            84 kB
+ First Load JS shared by all              83.6 kB
  ├ chunks/framework-fc97f3f1282ce3ed.js   44.9 kB
  ├ chunks/main-f4ae3437c92c1efc.js        28.3 kB
  ├ chunks/pages/_app-4897a2087ece2691.js  9.59 kB
  ├ chunks/webpack-69bfa6990bb9e155.js     769 B
  └ css/0343dc3e6093f50e.css               23.7 kB

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)(Static)  automatically rendered as static HTML (uses no initial props)

npx next buildを実行後、npx next exportを実行しましょう。
これによって、NetlifyやAWS Amplifyなどで静的サイトとして公開できるファイルが生成されます。

npx next export

warn  - Statically exporting a Next.js application via `next export` disables API routes.
This command is meant for static-only hosts, and is not necessary to make your application static.
Pages in your application without server-side data dependencies will be automatically statically exported by `next build`, including pages powered by `getStaticProps`.
Learn more: https://nextjs.org/docs/messages/api-routes-static-export
info  - Copying "public" directory
info  - Exporting (3/3)
Export successful. Files written to /Users/nextjs-stripe-ec/out

静的化したサイトを確認してみよう

静的化したファイルは、out/ディレクトリに配置されています。

npx serve outを実行しましょう。

npx serve out

┌───────────────────────────────────────────────┐
│                                               │
│   Serving!                                    │
│                                               │
│   - Local:                                    │
│   http://localhost:60270                      │
│   - On Your Network:                          │
│   http://192.168.1.7:60270                    │
│                                               │
│   This port was picked because 3000 is in     │
│   use.                                        │
│                                               │
│   Copied local address to clipboard!          │
│                                               │
└───────────────────────────────────────────────┘

静的化したサイトにアクセスするためのURLが表示されますので、URLをブラウザにコピー&ペーストしてアクセスします。

warn - Statically exporting a Next.js application via "next export" disables API routes.について

create-next-appで生成したアプリをnpx next exportすると、Warningが表示されます。

これは、pages/apiディレクトリにファイルを配置している場合に表示されるメッセージです。

next exportで静的化した場合、Next.jsのAPI機能は利用できません。

そのため、「pages/apiにファイルがあるけども、export後は使えません」と警告してくれています。

このステップではまだ利用していない機能ですので、このままにします。
実際にサイトを開発する時には、このwarningが出ていないかを確認するようにしましょう。

おさらい

  • Next.jsでは、静的サイトを出力することができる
  • next/imageやAPIなど、使えなくなる機能が一部ある
  • pages/_app.jsにレイアウトなどの共通要素を配置できる

次のステップでは、APIを利用したサーバーサイドの組み込みを体験しましょう。

「早く終わった」という方のための、もう1ステップ

Google Analyticsなどの外部JSライブラリの読み込みや、bodyタグにクラス名・属性を追加したい場合には、pages/_app.jsの代わりにpages/_documents.jsxを利用します。

公式ドキュメントを参考に、「bodyタグにクラス名を追加する」や「htmlタグにlang属性を追加する」ことに挑戦してみましょう。

https://nextjs.org/docs/advanced-features/custom-document