Next.js (現バージョン 9.4) に入門します。
何をするものか?
- Reactでウェブサイトを構築できます
- サーバサイドで動きます
- SSRできます
- APIも生やせます
- 静的サイトとしてもレンダリングできます
- サーバサイドで動きます
- 基本的にcreate-react-app (CRA)によく似ています
- CRAと同じで、設定がなくて楽ちんです
- CRAと同じで、裏で勝手にwebpackとか使ってます
- 特定のディレクトリに決まった形式でJSファイルを置けばページとしてルーティングとサーブとレンダリングをよしなにやってくれます
- ページに該当するJSからReactコンポーネントをexport defaultとして公開すればOKです。
-
./pages/xxx/index.tsx
→http://myhost/xxx/
-
./pages/foobar/baz.js
→http://myhost/foobar/baz
-
./pages/[var].js
→http://myhost/${var}.js
(パス変数を使う場合)- React側からは
useRouter().query.var
でアクセス可能。?xxx=yyyy
みたいなものをマージされてくる。
- React側からは
- ビルド時・SSR時などに評価させるにはコンポーネントとともに下記の関数をexportすればOK
- SSR時:
export const getServerSideProps: GetServerSideProps = async () => { ... }
- ビルド時:
export const getStaticProps: GetStaticProps = async () => { ... }
- パス引数に与えるパス変数のバリエーションを指定したい場合は
export const getStaticPaths: GetStaticPaths = async () => { ... }
でOK。ここで返却したパス変数のバリエーション分静的レンダリングされたHTMLが出来上がったりする。
- パス引数に与えるパス変数のバリエーションを指定したい場合は
- SSR時:
-
- APIは
./pages/api
以下で公開できます。- export defaultで
(req, res) => { ... }
みたいな関数を出力すればOK
- export defaultで
- ページに該当するJSからReactコンポーネントをexport defaultとして公開すれば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
フォルダを公開すればいい
- Node.js アプリとして:
- Vercel: 公式のデプロイサーバ
プロジェクト作成から起動まで
# プロジェクト作成
$ 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変換結果のキャッシュの邪魔になるからだそうです。
module.exports = {
plugins: ["tailwindcss"],
};
module.exports = {
purge: ["./pages/**/*.js", "./pages/**/*.tsx"], // 好きにふやしましょう
theme: {
extend: {},
},
variants: {},
plugins: [],
};
pages/index.css
も作っておきましょう。
@tailwind base;
@tailwind components;
@tailwind utilities;
グローバルから参照するように設定します。
import { AppProps } from "next/app";
import "./index.css";
export default ({ Component, pageProps }: AppProps) => {
return <Component {...pageProps} />;
};
twin.macro / Babelの設定 (.babelrc)
twin.macro側にNext.jsと併用する時のガイドがありますが、ベーシックなものでいきます。
{
"presets": ["next/babel"],
"plugins": ["babel-plugin-macros"]
}
上記に加え、emotionのcssプロパティを使う場合、 "presets"
に "@emotion/babel-preset-css-prop"
を追加すればいいようです。
ここまでの構成の確認
サイトのフロントカバーを作成してみます。
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()}
などを入れると分かりやすいと思います。
サイトを発展させる
何も無いのは寂しいので、全ページの一番上にグローバルナビを追加してみましょう。
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
の方に追記したほうがいいと思われます…
プロファイルのページも足しましょう。
export default () => <h2 className="text-6xl">好きな食べ物はうどん!</h2>;
まとめ
SSRしたり色々するのに非常に楽なプラットフォームだと思いました。
なんとなくReactアプリをCRAではじめるのもアリですが、Next.jsのほうがハマるパターンも結構あると思います。