Next.jsのプロジェクトを始める際にテンプレート的に行っていることを記載します。
ざっくり以下の手順で進めます。
- 前準備
- Next.jsの初期化
- Prettierの設定
- ESLintの設定
検証した環境
1 | Next.js | 14.1.3 |
2 | pnpm | 8.15.3 |
3 | volta | 1.1.1 |
4 | prettier | 3.2.5 |
前準備
GitHubの準備
GitHubでプロジェクトを前もって作成します。
ここではnextjs-base
という名前で作成しました。
私はghqを使ってリポジトリ管理をしているのでghqを使ってcloneします
ghq get git@github.com:yuki-takara/nextjs-base.git
作成したリポジトリのフォルダでgit関連の初期化を行います
# 作成したリポジトリのフォルダに移動
cd {作成したリポジトリのフォルダ}
# GitHub上に表示されている初期化のコマンドをそのままコピペ
echo "# nextjs-base" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:yuki-takara/nextjs-base.git
git push -u origin main
first commit
がコミット出来て、GitHub上に連携出来ていればOK!
$ git log --oneline
26eea93 (HEAD -> main, origin/main) first commit
nodeの設定
せっかくなのでnodeのバージョン管理としてvoltaを利用してみます!
voltaを使う上でpackage.jsonを用意します
pnpm init
pakage.jsonが作られるので最低限のものを残しつつ編集します
{
"name": "nextjs-base",
"version": "0.0.1",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "ISC"
}
voltaの記述を追記、記述時点のLTSを記載しました
{
"name": "nextjs-base",
"version": "0.0.1",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "ISC",
"volta": {
"node": "20.11.1"
}
}
$ node -v
v20.11.1
package.jsonに記載したvoltaでのバージョンが使えるようになりました!
Next.jsの初期化
公式ページに従って作成します
https://nextjs.org/docs/getting-started/installation
pnpm dlx create-next-app@latest
聞かれる質問は全てデフォルトのまま進めました
✔ What is your project named? … my-app
✔ Would you like to use TypeScript? … Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like to use `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to customize the default import alias (@/*)? … No
階層を深くする理由が特にないので、
my-appとして作成した中身を隠しファイルも含めて移動します
package.jsonも上書きされるのでnameやvoltaの記述を更新します
{
"name": "nextjs-base",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "^18",
"react-dom": "^18",
"next": "14.1.3"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"eslint": "^8",
"eslint-config-next": "14.1.3"
},
"volta": {
"node": "20.11.1"
}
}
dev環境が起動することを確認していきます
$ pnpm run dev
> nextjs-base@0.0.1 dev /Users/yuu/src/github.com/yuki-takara/nextjs-base
> next dev
▲ Next.js 14.1.3
- Local: http://localhost:3000
http://localhost:3000 にアクセスして開発環境が動作しました!
Prettierの設定
FormatterにPrettierを導入します
Biome も話題に上がってますが、まだPrettierが一般的なイメージが強いためここではPrettierにしました。
pnpm add -D prettier
Prettierの設定ファイルは .prettierrc
.prettierrc.js
等、様々な形式で用意が可能です。
ここでは prettier.config.js
として作成していきます
module.exports = {
endOfLine: "lf",
semi: false,
singleQuote: true,
printWidth: 100,
arrowParens: 'avoid',
}
Prettierの設定は好みが出るところで私は↑のような設定することが多いです。
「コメントが出来る」 という点で .js
か .yml
のファイル種類を選ぶのが理想形なイメージがあり私は .prettierrc.js
とする事が多かったのですが、
海外の方のリポジトリを見る限り prettier.config.js
とされている事が多いように感じました 📝
Googleのコーディングガイドを参考にすると以下のようになるそうです
(ChatGPT先生にお願いしたら作ってくれました。ありがた過ぎる。。)module.exports = {
// Googleスタイルガイドに従い、インデントには2つのスペースを使用
tabWidth: 2,
// セミコロンを省略せずに使用
semi: true,
// シングルクォートを使用
singleQuote: true,
// オブジェクトのプロパティのキーが必要な場合のみクォートを使用
quoteProps: 'as-needed',
// 配列やオブジェクトの要素の最後にもカンマを付ける(ES5で有効な場合のみ)
trailingComma: 'es5',
// 複数行の場合、配列の括弧内に改行を入れる
bracketSpacing: true,
// アロー関数のパラメータが1つのみの場合も括弧を付ける
arrowParens: 'always',
// HTMLやJSXの閉じタグを改行しない
jsxBracketSameLine: false,
// HTMLやJSXの属性にシングルクォートを使用
jsxSingleQuote: true,
// ファイルの末尾に改行を入れる
endOfLine: 'lf',
};
最後にPrettierを全体的に実行して完了です!
pnpmのlockファイルがYAMLなので拡張子を指定してみましたpnpm dlx prettier --write "**/*.{ts,tsx,json,mjs,css}"
ESLintの設定
FormatterのPrettierでカバー出来ない部分はESLintで補ってもらいます
ここでは以前書いた記事の中から2つを取り入れることにしました
eslint-config-prettier
eslint-plugin-unicorn
少し前は airbnb
を入れるのが主流だったイメージが強いのですが、
最近はそんな事もなくなってきている感覚があったため↑に記載した2つにしました
.eslintrc.json → .eslintrc.js
Prettierと同じく.jsonだとコメントが出来ないため、
ESLintの設定ファイルの拡張子を前もって .js
に変更します
{
"extends": "next/core-web-vitals"
}
module.exports = {
extends: 'next/core-web-vitals',
}
eslint-config-prettier
PrettierとESLintの設定がバッティングしないようにします
pnpm add -D eslint-config-prettier
module.exports = {
extends: ['next/core-web-vitals', 'prettier'],
}
設定を更新してLintで怒られないことを確認します
$ pnpm run lint
> next lint
✔ No ESLint warnings or errors
eslint-plugin-unicorn
More than 100 powerful ESLint rules
と書かれているように、ESLintをより強力にするルール集です!
1度使ってみたらハマってしまってほぼ全てのプロジェクトに導入しています 😂
pnpm add -D eslint-plugin-unicorn
module.exports = {
extends: ['next/core-web-vitals', 'plugin:unicorn/recommended', 'prettier'],
}
設定を更新してLintで怒られ、、ない?
$ pnpm run lint
> next lint
✔ No ESLint warnings or errors
以前だとこの段階で怒られていた記憶があるものの
これだとちゃんと適用出来ているか分からないのでちゃんと効いているか確認していきます
eslint-plugin-unicorn
は厳しいルールも多いため、
適宜ルールの変更・停止等行ってプロジェクトに合わせていく必要が出てきます。
プロジェクト途中で導入するとLintの対応だけでかなりの時間を使うケースも往々にして起こり得ます
ESLint周りの修正
SampleComponent
というコンポーネントを追加し、page.tsxで読み込ませます
'use client'
import { useState } from 'react'
export function SampleComponent() {
const [val, setVal] = useState(0)
return <div>{val}</div>
}
import Image from 'next/image'
import { SampleComponent } from '@/components/SampleComponent'
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<SampleComponent />
・・・
これでESLintを実行してみるとバッチリ怒られます
$ pnpm run lint
> next lint
./src/components/SampleComponent.tsx
1:1 Error: Filename is not in kebab case. Rename it to `sample-component.tsx`. unicorn/filename-case
6:10 Error: The variable `val` should be named `value`. A more descriptive name will do too. unicorn/prevent-abbreviations
6:15 Error: The variable `setVal` should be named `setValue`. A more descriptive name will do too. unicorn/prevent-abbreviations
- 1はファイル名をケバブケースにしよう
- 2,3はもっと分かりやすい名前にしよう
というものです。
ファイル名はケバブケースではなくキャメルケースで書くことも多いためルール自体offにし、
もう1つの指摘内容は修正していきます
module.exports = {
extends: ['next/core-web-vitals', 'plugin:unicorn/recommended', 'prettier'],
rules: {
// ケバブケース以外のファイル名も許容
'unicorn/filename-case': 'off',
},
}
'use client'
import { useState } from 'react'
export function SampleComponent() {
const [value, setValue] = useState(0)
return <div>{value}</div>
}
改めてESLintを実行してみると
$ pnpm run lint
> next lint
✔ No ESLint warnings or errors
バッチリです!🙌
余談
アイキャッチは最近ChatGPT先生に作ってもらってまして、
ボツ案としてこんなのも作ってくれました。
いちいち載せたくなるカッコ良さがあるんですよね 😂