Next.js14の環境構築をテンプレート化したい🔫💨[2023]
今回やること 🧩
- Next.js(App router)環境のアプリ構築
- 以前書いた記事を元に ESLint の導入
- Prettier の導入
- Husky + lint-staged の導入で ESLint と Prettier の自動化
成果物 🦋
環境
{
"name": "template-next",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"format": "prettier --write",
"prepare": "husky install"
},
"dependencies": {
"next": "14.0.4",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"autoprefixer": "^10.0.1",
"eslint": "^8",
"eslint-config-next": "14.0.4",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-simple-import-sort": "^10.0.0",
"husky": "^8.0.0",
"lint-staged": "^15.2.0",
"postcss": "^8",
"prettier": "^3.1.1",
"tailwindcss": "^3.3.0",
"typescript": "^5"
}
}
Next.js アプリケーションの作成 💧
Node のバージョンを確認
前提としてNode.js 18.17
以降が必要です。
$ node -v
v20.10.0
create-next-app
全て Yes で設定!
npx create-next-app@latest
Need to install the following packages:
create-next-app@14.0.4
Ok to proceed? (y)
✔ What is your project named? … template-next
✔ 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 (@/*)? … Yes
? What import alias would you like configured? › @/*
最後の? What import alias would you like configured? › @/*
については、
ファイルパスの先頭に@/と指定するとプロジェクトディレクトリとなるようエイリアスの設定をしてます 🪽
import { Sample } from '../../../components/sample';
↓ こんな感じ
import { Sample } from '@/components/sample';
確認
すでに最低限ですがセットアップは完了しているため開発サーバーを起動してみる 🖲️
npm run dev
↓
> template-next@0.1.0 dev
> next dev
▲ Next.js 14.0.4
- Local: http://localhost:3000
このようになっていれば 🥳
Prettier の設定 🤸🏾♂️
インストール
npm install -D prettier
設定を追加
{
"semi": false,
"singleQuote": true,
"trailingComma": "all"
}
scripts も追加しておく
{
"scripts": {
~~
+ "format": "prettier --write",
}
}
vscode の拡張を追加
ESLint🧊
以前書いた記事を参考に作成していく
インストール
create-next-app
時にeslint
の install は終わっているがルール関連のインストールがまだのため追加していきます
npm install -D @typescript-eslint/eslint-plugin eslint-plugin-eslint-comments @typescript-eslint/parser eslint-config-prettier eslint-plugin-import eslint-plugin-react eslint-plugin-simple-import-sort
独自設定するルール一覧
コーディング規約に基づいて以下のルールを追加します 💫
- eslint-disable を使う場合はコメント必須!
- マジックナンバー禁止
- import/export の sort
- 型定義は type を使う
- any 禁止
- 未使用の変数を残さない
- 自己閉じタグを使う
<Component />
- boolean の属性表記は省略形
- 省略可能な object key は省略する
{data: data} → {data}
- 原則 default export 禁止
- app router では
page.tsx
に当たるものがルーティングされるためルールから除外する
- app router では
- アロー関数を使う
- 命名規則の設定
ルールを追加
記事に合わせるため.eslintrc.json
→.eslintrc.js
に変更する(深い意味はないです!)
module.exports = {
extends: [
'next/core-web-vitals',
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:react/jsx-runtime',
'plugin:eslint-comments/recommended',
'prettier',
],
env: { browser: true, node: true, es6: true },
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint', 'simple-import-sort', 'import'],
ignorePatterns: ['node_modules/', '.eslintrc.js'],
rules: {
'react/jsx-curly-brace-presence': 'warn',
'simple-import-sort/imports': 'error', //importとexportのソート
'simple-import-sort/exports': 'error',
'import/first': 'error',
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
'@typescript-eslint/consistent-type-definitions': ['warn', 'type'], //型定義はtypeを使う
'@typescript-eslint/no-explicit-any': 'error', //any禁止
'@typescript-eslint/no-unused-vars': 'error', //未使用の変数禁止
'react/self-closing-comp': ['error', { component: true, html: true }], //<Component />のように自己閉タグを使う
'no-control-regex': 'off', //正規表現中のASCII制御文字ok
'react/jsx-boolean-value': 'error', //attribute={true} → attribute
'react/jsx-pascal-case': 'error', //コンポーネント名はパスカルケース
'object-shorthand': ['warn', 'properties', { avoidQuotes: true }],
'eslint-comments/require-description': 'error', //eslint-disable-next-lineのコメントは必ず説明を書く。https://mysticatea.github.io/eslint-plugin-eslint-comments/rules/require-description.html
'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], //https://mysticatea.github.io/eslint-plugin-eslint-comments/rules/disable-enable-pair.html
'import/no-default-export': 'error', //default export禁止
'no-nested-ternary': 'error', //三項演算子のネスト禁止
'react/function-component-definition': [
'error', //関数コンポーネントの定義はアロー関数を使う
{ namedComponents: 'arrow-function' },
],
'no-magic-numbers': [
'error',
{
ignore: [-1, 0, 1], //配列検索でindexOf === -1などは許容する
ignoreDefaultValues: true, //const { tax = 0.1 } = props
ignoreArrayIndexes: true, //data[100] ok
enforceConst: true, //マジックナンバーはconstで定義する
},
],
'@typescript-eslint/naming-convention': [
'error',
{
selector: ['variable', 'method', 'accessor'], //基本的に全てcamelCase
format: ['camelCase', 'snake_case'],
},
{
selector: ['property'], //APIリクエスト時にPascalCaseとなっている箇所がある
format: ['camelCase', 'snake_case', 'PascalCase'],
},
{
selector: 'variable', //exportされている定数やコンポーネント
modifiers: ['exported', 'const'],
format: ['PascalCase', 'strictCamelCase'],
},
{
selector: 'interface', //interfaceはIをつけない
format: ['PascalCase'],
custom: { regex: '^I[A-Z]', match: false },
},
{ selector: ['class', 'typeAlias', 'enum'], format: ['PascalCase'] },
{
selector: ['objectLiteralProperty'], //api requestのheadersの'Content-Type'などが対応するためnullで許容する
format: null,
modifiers: ['requiresQuotes'],
},
],
},
overrides: [
{
files: ['*/app/**/page.tsx', 'layout.tsx', 'tailwind.config.ts'],
rules: {
'import/no-default-export': 'off',
'import/prefer-default-export': 'error',
'@typescript-eslint/naming-convention': 'off',
},
},
],
}
vscode の拡張を設定
Husky + lint-staged の設定 🧃
Husky のインストール
npx husky-init && npm install
lint-staged のインストール
npm install -D lint-staged
.husky/pre-commit
にコマンドを追加
npx husky set .husky/pre-commit "npx lint-staged"
以下のようになれば ✅
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
ステージングに上がっているファイルのみを対象とする設定を追加
If you would like to use next lint with lint-staged to run the linter on staged git files, you'll have to add the following to the .lintstagedrc.js file in the root of your project in order to specify usage of the --file flag.
Next.js ではnext lint
とlint-staged
を併用したい場合は以下の設定が必要なため新しく.lintstagedrc.js
を作成していきます
const path = require('path')
const buildEslintCommand = (filenames) =>
`next lint --fix --file ${filenames
.map((f) => path.relative(process.cwd(), f))
.join(' --file ')}`
module.exports = {
'*.{js,jsx,ts,tsx}': [
() => 'tsc --incremental false --noEmit',
buildEslintCommand,
'prettier --write',
],
}
公式では ESLint の設定のみの記載のため() => 'tsc --incremental false --noEmit'
で型コンパイルエラーのチェックを入れました 🤹♂️
完成!👩🎤
最後に確認をしていきます 🦑
- ESLint が効いているか適当にコードを書いてみる
🤮 コード
3 つのルール違反をしています
- 使っていない定数
- マジックナンバー
- eslint-disable にコメントを書かない
"use client";
import { FC, useEffect, useState } from "react";
const unused = "unused";
const Sample: FC = () => {
const [data, setData] = useState<string>("");
useEffect(() => {
if (!data) return;
if (data.length === 1000000) {
console.log("condition is 1000000");
}
setData("data");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div>
<p>Sample</p>
</div>
);
};
export default Sample;
:::
- lint-staged
実行結果
ok!🧼
git commit -m "lint-stagedの確認"
✔ Preparing lint-staged...
⚠ Running tasks for staged files...
❯ .lintstagedrc.js — 1 file
❯ *.{js,jsx,ts,tsx} — 1 file
✔ tsc --incremental false --noEmit
✖ next lint --fix --file src/app/sample/page.tsx [FAILED]
◼ prettier --write
↓ Skipped because of errors from tasks.
✔ Reverting to original state because of errors...
✔ Cleaning up temporary files...
✖ next lint --fix --file src/app/sample/page.tsx:
./src/app/sample/page.tsx
4:7 Error: 'unused' is assigned a value but never used. @typescript-eslint/no-unused-vars
11:25 Error: No magic number: 1000000. no-magic-numbers
Error: Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary. eslint-comments/require-description
info - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
husky - pre-commit hook exited with code 1 (error)
:::
ありがとうございました!🌈❤️🔥🎅🦞🎈
スクラップはこちら
Discussion