📔

Next.js + TypeScriptで雛形環境をテンプレート化する

9 min read

はじめに

個人でも実務でもNext.jsに触れることが増えてきました。
何度も同じ手順で環境を作るのはやはり手間ですし、あそこどうしてたっけ?となって都度調べるのも避けたいです。

この記事では、Next.js+TypeScriptの雛形環境をサクっと構築し、
それをテンプレートとして再利用するまで(これが本題)の手順を一通りまとめています。

調査した内容など勉強を兼ねて1つしっかり手順をアウトプットしておこうと思います。
ただ、こういったものは時間と共にやり方も徐々に変わっていくものだと思うので、そこは都度アップデートしていければと考えています。

前提

  • GitHubアカウントの所持
  • Gitをインストール済み
  • nodeをインストール済み
  • yarn/npmが実行できる(今回はyarnです)

環境

最終的には以下のようになります。

package.json
"dependencies": {
  "next": "12.0.4",
  "react": "17.0.2",
  "react-dom": "17.0.2"
},
"devDependencies": {
  "@types/node": "16.11.9",
  "@types/react": "17.0.35",
  "@typescript-eslint/eslint-plugin": "^5.4.0",
  "eslint": "7.32.0",
  "eslint-config-next": "12.0.4",
  "eslint-config-prettier": "8.3.0",
  "prettier": "2.4.1",
  "sort-package-json": "^1.53.1",
  "typescript": "4.5.2",
  "yarn-run-all": "^3.1.1"
}

大まかな流れ

  1. GitHubリポジトリの準備
  2. Next.jsプロジェクトの作成
  3. 各種ページ、コンポーネントなどの準備と調整
  4. ESLint+Prettierの導入と設定
  5. テンプレートとして再利用する方法の紹介
  6. おまけ

環境構築手順

新規リポジトリを作成

まずはGitHub上で今回のプロジェクト用のリポジトリを作成してください。
リポジトリ名はテンプレートであることが分かるようなものが良いでしょう。

注意点
Initialize this repository with:の項目内のAdd a READNE fileはチェックを入れないでください

プロジェクトを作成

mynextappの部分は自由に変更することができます。

ターミナル
# プロジェクト作成
npx create-next-app --typescript mynextapp

# プロジェクトフォルダへ移動
cd mynextapp

# 実行
yarn dev

問題無ければ http://localhost:3000 でページの確認ができます。

srcディレクトリを作成

各ソースコードをsrc配下にまとめていくようにします。
こちらは好みですが、個人的にルートにディレクトリがばらつくのが嫌なのでソースはsrcへまとめていくこのパターンを採用しています。

ターミナル
# プロジェクトルートで
mkdir src && \
mv pages/ src/pages && \
mv styles/ src/styles

srcを基準に絶対パスでimportするように設定します。

tsconfig.json
# tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "src",
}

不要コード、ファイルの削除

トップページの不要コードを削除し以下のようにしてしまいます。

src/pages/index.tsx
import type { NextPage } from 'next';

const Home: NextPage = () => {
    return (
        <div>
            <h1>My Template</h1>
        </div>
    );
};

export default Home;

以下のファイルは削除、または適宜差し替えして下さい。

  • src/pages/api/hello.ts
  • src/styles/Home.module.css
  • public/favicon.ico
  • public/vercel.svg

レイアウトコンポーネントの作成

全てのページで共通で使うレイアウトのコンポーネントを作成します。

src/components/Layout.tsxを作成します。(中身はお好みで)

src/components/Layout.tsx
import Head from 'next/head';
import Link from 'next/link';
import { ReactNode } from 'react';

type Props = {
    children?: ReactNode;
};

const Layout = ({ children }: Props) => {
    return (
        <div>
            <Head>
                <title>MyTemplate</title>
            </Head>

            <header className=''>
                <Link href='/'>
                    <a>Home</a>
                </Link>
            </header>

            <div className='content'>{children}</div>

            <footer className=''></footer>
        </div>
    );
};

export default Layout;

全ページに共通レイアウトを適用します。

src/pages/_app.tsx
import 'styles/globals.css';
import Layout from 'components/Layout';
import type { AppProps } from 'next/app';

function MyApp({ Component, pageProps }: AppProps) {
    return (
        <Layout>
            <Component {...pageProps} />
        </Layout>
    );
}

export default MyApp;

カスタムドキュメントの作成

全ページ共通でheadタグやbodyタグなどのカスタマイズを行えるファイルを追加します。

src/pages/_document.tsxを作成します。(中身はお好みで)

src/pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document';

const MyDocument = () => {
    return (
        <Html lang='ja-JP'>
            <Head>
                <meta name='application-name' content='MyTemplate' />
                <meta name='description' content='' />
            </Head>
            <body>
                <Main />
                <NextScript />
            </body>
        </Html>
    );
};

export default MyDocument;

ESlintの設定

Next.js@11.0.0からcreate-next-appを使用した時点で導入が完了しているので、以下の基本的な設定のみ行います。

package.jsonでチェック対象のディレクトリを修正します。
精査するディレクトリを変更・追加する場合はお好みで。

package.json
"scripts": {
    "lint": "next lint --dir src"
},

追加のパッケージを導入します。

ターミナル
yarn add --dev @typescript-eslint/eslint-plugin

ESLintの設定ファイルを修正します。

.eslintrc.json
{
  "root": true,
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "plugins": ["@typescript-eslint"],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "next",
    "next/core-web-vitals",
  ],
  "rules": {
    // ここに追加したいルールをいれます
  }
}

Prettierを導入

必要なパッケージを導入します。

ターミナル
# パッケージ追加
yarn add --dev --exact prettier eslint-config-prettier

# Prettier設定ファイル追加
touch .prettierrc.json

Prettierの設定を追加します。(お好みで書き換えて下さい)

.prettierrc.json
{
  "tabWidth": 4,
  "semi": true,
  "singleQuote": true,
  "jsxSingleQuote": true,
  "arrowParens": "always",
}

ESLintとPrettierのコンフリクトを防ぐ設定を追加します。

.eslintrc.json
  ...
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "next",
    "next/core-web-vitals",
    "prettier" // ココを追加
  ],

Prettierでコードフォーマットを実行するコマンドを追記します。

package.json
"scripts": {
    ...
    "lint:fix": "eslint \"src/**/*.{ts,tsx,js,jsx}\" --fix",
    "format": "prettier --write --ignore-path .gitignore \"src/**/*.{ts,tsx,js,jsx,json,css,scss}\""
},

フォーマットが実行されるか確認するため、src/components/sample.tsxを作成し以下のコードを追加します。

src/components/format.tsx
export default function Format() {
  return (
    <div className="format test">
      hogehoge
    </div>
  )
}

formatコマンドを実行し、自身が設定したルールに従って整形される事を確認してください。
今回でいくと、セミコロンが付与されダブルクォーテーションがシングルクォーテーションになればOKです。

ターミナル
yarn format

ESLintとPrettierによるコマンドを毎回打つのは手間が掛かります。
自身のエディタでファイル保存時にコマンドが走るように設定すると捗るのでやっておくと良いです。
(人によって使用エディタが違うと思うので今回は省略します)

scriptsを順次/並列実行できるようにする

以下のパッケージを導入します。

ターミナル
yarn add --dev yarn-run-all

これまでに設定したESLintとPrettierのコマンドを順次実行するように追記します。

package.json
...
"scripts": {
    ...
    "lint": "next lint --dir src",
    "lint:fix": "eslint \"src/**/*.{ts,tsx,js,jsx}\" --fix",
    "format": "prettier --write --ignore-path .gitignore \"src/**/*.{ts,tsx,js,jsx,json,css,scss}\"",
    "test-all": "run-s lint format lint:fix" // ココを追加
  },

追記したコマンドを実行して動作を確認します。

ターミナル
yarn test-all

ブラウザで動作確認

yarn devコマンドを実行し http://localhost:3000 へアクセスして特に問題がないことを確認しておきます。

必要に応じて

かなり最小構成ですがここまでで基本的な環境が整いました。
その他、

  • husky + lint-stagedによるコード解析/整形の自動化
  • 状態管理ライブラリ
  • CSSフレームワーク
  • テストツール

などについては、個人か実務かまたは好みかで色々変わってきそうな所ですので必要に応じて導入を行ってください。

GitHubへpush

冒頭で作成したリポジトリと、ローカルに作ったリポジトリを紐付けます。
ターミナルでの手順ですがSourceTreeなどのGUIを使っても構いません。

{}内は予め作成したリモートブランチのリポジトリURLを指定します。

ターミナル
# ファイルをステージングしてコミット
git add .
git commit -m "first commit"

# リポジトリを紐付ける
git branch -M main 
git remote add origin {リポジトリのURLを指定}

# プッシュする
git push -u origin main

pushできたらリポジトリへアクセスして反映されているか確認しておきます。

テンプレートとして再利用する

長くなりましたが本題です。
今回の手順で設定済みのプロジェクトをテンプレートとして再利用する2つの方法です。

方法1. --exampleオプションを使う

次回からは以下のcreate-next-app--exampleオプションを使って、同様のプロジェクトを作れます。

{}内の部分はご自身の環境に合わせて指定してください。

ターミナル
create-next-app {プロジェクト名} --example {GitHubリポジトリURL}

URL末尾に.gitが入らないように注意してください。

create-next-app mysecondapp --example https://github.com/hoge/template-next-ts-eslint-prettier

方法2. GitHub Template Repositoryを使う

冒頭でGitHubにリポジトリを作成したと思います。
そのリポジトリへアクセスして、メニューのSettingsにあるTemplate Repositoryにチェックを入れます。

そうすると、リポジトリのトップページにUse this templateというボタンが右上に追加されます。
このボタンを押すだけでリポジトリ作成画面に遷移するので、あとはいつも通りにリポジトリを作れば出来上がりです。

お疲れ様でした。

おまけ:いいなと思ったツール

sort-package-json

package.jsonが綺麗になる!

yarn add --dev sort-package-json

設定

package.json
...
"scripts": {
    "sort": "sort-package-json package.json",
},

おまけ:導入をすすめたいライブラリ

何か発見したら追加していこうと思います。
是非みなさんのオススメもコメント欄で教えて下さい!

ページ上部に手軽に表示できるローディングバー。
Youtubeなどで読み込み時にびゅんって出るアレです。

ページ遷移時や何か時間の掛かる処理実行時など、「時間が掛かっているよ」ということをユーザーさんに視覚的に認識させやすくなります。
これだけでもかなりユーザー体験あがります。

導入もとても簡単なので是非採用してみてください。

https://github.com/rstacruz/nprogress

さいごに

今回記事を作るにあたって色々な方の投稿を見させて頂きとても勉強になりました。

最初の1度は少し大変ですが、汎用的に使えるプロジェクトを1個用意しておけば以降のスタートが大分楽になるので是非自分なりのベース環境を作ってみてください!

素のReact開発から最近Next.jsに移ってきたのですがあまりの便利さ、開発のしやすさに驚きました。しばらくはNext.jsから離れられなさそうです。
まだまだ勉強中の身ではありますが、本記事の内容に気になる点があればお気軽にご指摘、ご意見頂ければ大変助かります。

この記事が少しでも誰かの役に立てば幸いです。
ここまで見て頂きありがとうございました。

Discussion

ログインするとコメントできます