LoginSignup
32
25

More than 3 years have passed since last update.

Next.js に入門してみた

Last updated at Posted at 2020-05-31

Next.js (現バージョン 9.4) に入門します。

何をするものか?

  • Reactでウェブサイトを構築できます
    • サーバサイドで動きます
      • SSRできます
      • APIも生やせます
    • 静的サイトとしてもレンダリングできます
  • 基本的にcreate-react-app (CRA)によく似ています
    • CRAと同じで、設定がなくて楽ちんです
    • CRAと同じで、裏で勝手にwebpackとか使ってます
  • 特定のディレクトリに決まった形式でJSファイルを置けばページとしてルーティングとサーブとレンダリングをよしなにやってくれます
    • ページに該当するJSからReactコンポーネントをexport defaultとして公開すればOKです。
      • ./pages/xxx/index.tsxhttp://myhost/xxx/
      • ./pages/foobar/baz.jshttp://myhost/foobar/baz
      • ./pages/[var].jshttp://myhost/${var}.js (パス変数を使う場合)
        • React側からは useRouter().query.var でアクセス可能。 ?xxx=yyyy みたいなものをマージされてくる。
      • ビルド時・SSR時などに評価させるにはコンポーネントとともに下記の関数をexportすればOK
        • SSR時: export const getServerSideProps: GetServerSideProps = async () => { ... }
        • ビルド時: export const getStaticProps: GetStaticProps = async () => { ... }
          • パス引数に与えるパス変数のバリエーションを指定したい場合は export const getStaticPaths: GetStaticPaths = async () => { ... } でOK。ここで返却したパス変数のバリエーション分静的レンダリングされたHTMLが出来上がったりする。
    • APIは ./pages/api 以下で公開できます。
      • export defaultで (req, res) => { ... } みたいな関数を出力すればOK

○○できるの?

ドキュメント見ればだいたい書いてありますが…

  • Babel: できる
  • PostCSS: できる
  • TypeScript: できる
  • CSS in JS: できる
    • ビルトインのものがあるけどEmotionと組み合わせたりしたほうが便利そう
  • .env による環境変数指定: できる
  • APIサーバ: できる
  • PWA: こういうのもあるようです
  • 環境変数によるソース内文字列置換: できる
    • NEXT_PUBLIC_ で始めればOK
  • AMP: できる
  • ほかのNode.jsのHTTPサーバの一部に組み込む: できる
  • エラードキュメント: できる
  • プラグイン: ある
    • next.config.js (Next.jsの設定ファイル)にプラグインをrequireして記述すればOK
  • デプロイ: できるに決まってる
    • Vercel: 公式のデプロイサーバ
      • 基本的に無料
        • 別に静的ホスティングじゃなくて、APIとか動かしても無料
      • じゃあ何が有料なのかというと、
        • (Pro)チームコラボ・並列ビルド・パスワード保護・プレビューデプロイ
        • (Enterprise)SLA保証・マルチリージョンサーバレス機能・エンタプライズサポートなど
    • 自前:
      • Node.js アプリとして: next build しておいて、 next start すればOK
      • 静的サイトの場合は、 next build しておいて、 next export したら、できあがった /out フォルダを公開すればいい

プロジェクト作成から起動まで

# プロジェクト作成
$ yarn create next-app
 → Default ... を選択

# 開発サーバ起動
$ yarn dev

# ビルド
$ yarn build

# 本番サーバ起動 (yarn buildしないと失敗する)
$ yarn start
 → http://localhost:3000

TypeScript

ほぼ構成をカスタマイズする余地がありません。おまかせですね。

# 追加
$ yarn add -D typescript @types/react @types/node

# tsconfig.json というファイルがあれば Next.js が起動時に勝手に中身を書き込んでくれる。つまりカスタマイズするだけ無駄。
$ touch tsconfig.json

$ yarn dev
 → tsconfig.json / next-env.d.ts (型定義) が作成される

基本的には @babel/preset-typescript によるトランスパイルっぽいです。

あとは好きに *.tsx 置けば勝手にやってくれます。

ディレクトリ

  • public/
    • CRAと同じ。ここに公開できる静的ファイルを置く
  • pages/
    • ページ置き場ここ。 src/pages より優先される。
  • src/
    • pages/
      • ${projectRoot}/pages/ のかわりにおくことができる
  • .next/
    • next build でできるビルドディレクトリ
  • out/
    • next export でできるビルドディレクトリ

Next.js + TypeScript + Tailwind CSS (PostCSS) + twin.macro (Babel) + emotion で適当なサイトを作ってみる

リポジトリは https://github.com/knjname/2020-05-31_tryoutNextJs にあります。

初期化

# Next.js
$ yarn create next-app

# TypeScript
$ yarn add -D typescript @types/react @types/node
$ touch tsconfig.json

# Tailwind CSS
$ yarn add -D tailwindcss

# emotion
$ yarn add @emotion/core @emotion/styled

# twin.macro
$ yarn add -D babel-plugin-macros twin.macro

Tailwind CSS / PostCSSの設定 (postcss.config.js)

requireは使ってはいけないそうです。 CSS変換結果のキャッシュの邪魔になるからだそうです。

postcss.config.js
module.exports = {
  plugins: ["tailwindcss"],
};
tailwind.config.js
module.exports = {
  purge: ["./pages/**/*.js", "./pages/**/*.tsx"], // 好きにふやしましょう
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
};

pages/index.css も作っておきましょう。

pages/index.css
@tailwind base;

@tailwind components;

@tailwind utilities;

グローバルから参照するように設定します。

pages/_app.tsx
import { AppProps } from "next/app";
import "./index.css";

export default ({ Component, pageProps }: AppProps) => {
  return <Component {...pageProps} />;
};

twin.macro / Babelの設定 (.babelrc)

twin.macro側にNext.jsと併用する時のガイドがありますが、ベーシックなものでいきます。

.babelrc
{
  "presets": ["next/babel"],
  "plugins": ["babel-plugin-macros"]
}

上記に加え、emotionのcssプロパティを使う場合、 "presets""@emotion/babel-preset-css-prop" を追加すればいいようです。

ここまでの構成の確認

サイトのフロントカバーを作成してみます。

pages/index.tsx
import styled from "@emotion/styled";
import tw from "twin.macro";
export default () => (
  <div>
    <section
      style={{
        backgroundImage:
          'url("https://images.unsplash.com/photo-1590690726331-cd7699f1a415?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max")',
      }}
      className="w-screen h-screen bg-no-repeat bg-cover flex justify-center items-center"
    >
      <Component>
        <span className="text-pink-400">M</span>y biograph
        <span className="text-green-400">y</span>
      </Component>
    </section>
  </div>
);

const Component = styled.h1`
  ${tw`text-gray-100 uppercase font-semibold text-6xl`}
`;

実行(yarn dev)すると、無事(趣味の悪い)フロントカバーが出てきます。

このサイトを静的HTMLとしてエクスポートしてみます。

$ yarn build && yarn next export

$ npx http-server out
// => http://127.0.0.1:8080/

以下の点を確認してみましょう。

  • リンクされているCSSがきちんと必要なクラスだけ含んでいるかなど確認できます。(TailwindCSS/PurgeCSS)
  • また、DevToolsなどでJavaScriptを無効にしてもきちんと表示されることを確認することができます。
    • JavaScriptが有効であれば、この後 SSRされた内容とJavaScript側のReactコンポーネントのhydrate処理(同期処理)が行われるはずです。
    • ページの内容に {new Date().toString()} などを入れると分かりやすいと思います。

サイトを発展させる

何も無いのは寂しいので、全ページの一番上にグローバルナビを追加してみましょう。

src/_document.tsx
import Document, { Html, Head, Main, NextScript } from "next/document";
import Link from "next/link";

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    return { ...initialProps };
  }

  render() {
    const ListClassName = "text-white px-2";

    return (
      <Html>
        <Head />
        <body>
          <ul className="block flex px-4 py-2 bg-gray-800 sticky top-0 left-0">
            <li className={ListClassName}>
              <Link href="/">
                <a>Top</a>
              </Link>
            </li>
            <li className={ListClassName}>
              <Link href="/profile">Profile</Link>
            </li>
          </ul>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

(2020/06/02 追記) 上記のグローバルメニューですが、 _app.tsx の方に追記したほうがいいと思われます…

プロファイルのページも足しましょう。

src/profile.tsx
export default () => <h2 className="text-6xl">好きな食べ物はうどん!</h2>;

まとめ

SSRしたり色々するのに非常に楽なプラットフォームだと思いました。

なんとなくReactアプリをCRAではじめるのもアリですが、Next.jsのほうがハマるパターンも結構あると思います。

32
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
25