【TypeScript】Next.js + Tailwind CSSを使用してさくっとSPAを作る方法
Next.js で簡単な SPA の雛形をつくる際の手順です。
ホームページを Flutter Web から Next.js に移行した際に少し躓いたので整理して記録します。
追記:この記事では従来のWEBアプリケーション(MPA)の対義語としてSPAと表記しています。Next.jsがSPAに分類されるかは様々な意見があるので混乱を招いたかもしれません。たくさんのLIKEと反応ありがとうございます。
環境
執筆時点での各種バージョンです。
- Node: 14.17
- Next.js: 12.0.4
- Tailwind CSS: 2.2.19
- TypeScript: 4.5.2
Next.js プロジェクトの作成
下記コマンドで Next.js プロジェクトを作成します。
CreateNextApp を使用すると簡単に TypeScript 対応できて便利ですね。
$ npx create-next-app --typescript myapp
ソースファイルを src 配下に変更
これは好みですが、ファイルツリーで components と pages ディレクトリが離れてしまうのが嫌なので自分は src ディレクトリにまとめています。
src ディレクトリを作成しページとコンポーネントをそこへ移動します。
styles ディレクトリは今回使用しないため削除しても構いません。
TypeScript の設定
必要に応じて TypeScript の設定ファイルである tsconfig.json を編集します。
"compilerOptions": {
"baseUrl": ".",
・・・
}
Tailwind CSS の追加
Tailwind CSS と関連パッケージをインストールします。
$ npm i -D tailwindcss@latest postcss@latest autoprefixer@latest
続いてコマンドで設定ファイルを作成します。
$ npx tailwindcss init -p
tailwind.config.js が作成されるのでエディタで開きます。
mode と purge プロパティを下記のように変更します。
JIT モードはバージョン 2.1 から実装されたようで、指定すると開発中のパフォーマンスが向上するそうです。
module.exports = {
mode: "jit",
purge: [
"./src/pages/**/*.{js,ts,jsx,tsx}",
"./src/components/**/*.{js,ts,jsx,tsx}",
],
・・・
purge に指定するパスは環境に合わせて適宜変更してください。
パスが間違っているとうまくホットリロードされません。
最後に_app.tsx にインポートを追加します。
import "tailwindcss/tailwind.css";
・・・
Document をカスタマイズする
pages/_document.tsx ファイルを作成すると HTML や HEAD タグのデフォルトを変更できます。
import { Html, Head, Main, NextScript } from "next/document";
const MyDocument = () => {
return (
<Html lang="ja-JP">
<Head>
<meta name="application-name" content="MyApp" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
};
export default MyDocument;
- Html や Head は Next.js のコンポーネントなので、先頭が大文字であることに注意。<Main />も同様で、<main>とは異なります。
- <Head>がないとTailWindCssが動作しないので1つ以上要素を指定します。
ページを作成する。
デフォルトの index.tsx を編集してページの雛形を作成します。
今回はサンプルのため index ページと about ページだけの最小構成です。
import type { NextPage } from "next";
import Head from "next/head";
const Home: NextPage = () => {
return (
<div>
<Head>
<title>Index Page</title>
</Head>
<main>
<h1>ここはトップページです</h1>
</main>
</div>
);
};
export default Home;
同様に概要ページも作成します。
import type { NextPage } from "next";
import Head from "next/head";
const About: NextPage = () => {
return (
<div>
<Head>
<title>About Page</title>
</Head>
<main>
<h1>ここは概要ページです</h1>
</main>
</div>
);
};
export default About;
共通レイアウトを作成する
ナビゲーションやフッターなどの共通レイアウトを全てのページに書くのは面倒なので
全てのページをラップする Layout コンポーネントを作成します。
今回はシンプルなナビゲーションを作成しました。
Link コンポーネントを使用するとページ間がシームレスに移動できます。
import Link from "next/link";
import { ReactNode } from "react";
const Layout = ({ children }: Props) => {
return (
<div>
<nav className="flex flex-rows p-2 bg-red-500 text-white font-bold">
<Link href="/">
<a>Home</a>
</Link>
<Link href="/about">
<a>About </a>
</Link>
</nav>
{children}
</div>
);
};
type Props = {
children?: ReactNode;
};
export default Layout;
Tailwind CSS を使うと直感的にスタイルを変更できて便利ですね!
続いて全てのページを囲むように_app.tsx を変更します。
import "tailwindcss/tailwind.css";
import type { AppProps } from "next/app";
import Layout from "../components/layout";
function MyApp({ Component, pageProps }: AppProps) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
export default MyApp;
ブラウザで動作確認をする
下記のコマンドで開発サーバーを立ち上げ、ブラウザから「http://localhost:3000」を確認します。
$ npm run dev
CreateNextApp はホットリロードが組み込まれています。
そのため開発サーバーが起動している間はファイルが変更される度にコンパイルが実行され、すぐにブラウザに反映されます。
静的 HTML としてエクスポートする
Next.js はサーバー側でページを作成する SSR が有名ですが、ビルド時に API からデータを取得して静的 HTML を生成する SSG も可能です。
そのため、Netlify や Firebase など様々なホスティングサービスにデプロイできます。
ただし画像の最適化などの素晴らしい機能は SSG では使えないため、Next.js の機能をフルに使うには公式サービスの Vercel へデプロイするのが一番です。
package.json を変更してエクスポート用のスクリプトを追加します。
"scripts": {
"export": "next build && next export",
・・・
}
下記コマンドを実行すると out ディレクトリに静的 HTML が生成されます。
$ npm run export
まとめ
自分は素の React での開発経験しかなかったので、ルーティング機能や SSG などがデフォルトで提供されている Next.js に初めて触れてあまりの便利さに驚嘆しました。
Tailwind CSS はコンポーネントと同じファイルに直感的に書けるので Next.js と組み合わせると開発がさらに加速しそうですね。
以上です。
Discussion