本文へスキップ
メニュー
テーマ

Next.js開発環境構築(App Router, TypeScript, Tailwind CSS対応)

目次

はじめに

Next.jsの自分の開発環境が変わったので、備忘録として一連のツール導入までを残しておきます。

開発環境

  • Next.js(App Router)
  • TypeScript
  • Tailwind CSS + shadcn/ui
  • Prettier
  • ESLint
  • Storybook
  • husky + lint-staged
注意

この記事の手順は、書いた2024年9月時点のもの(Next.js 14・ESLint 8・Tailwind CSS 3・Storybook 8)です。2026年10月時点の最新版では、次の点が変わっています。

  • create-next-appの質問が変わりました。最初に推奨の設定を使うかを聞かれ、カスタマイズを選ぶと、リンターをESLint・Biome・なしから選びます。
  • Next.js 16でnext lintコマンドは削除されました。リントはESLintのCLI(eslint .)で実行します。
  • ESLintは、9から設定ファイルがeslint.config.js(Flat Config)になり、10で.eslintrc.jsonと.eslintignoreは使えなくなりました。この記事のESLintの設定は、Flat Configの書き方に直す必要があります。
  • shadcn/uiは、新しいプロジェクトではTailwind CSS v4が前提になり、初期化のときの質問も変わっています。

Upgrading: Version 16 | Next.js⁠(新しいタブで開く)

Configuration Migration Guide - ESLint - Pluggable JavaScript Linter⁠(新しいタブで開く)

Next.js

以下のコマンドを実行してNext.jsのプロジェクトを作成します。

ターミナルbash · 1行
npx create-next-app@latest <プロジェクト名>

質問にはすべてそのままで回答します。

.env.env · 6行
✔ 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

tsconfig.json

お好みですが、以下の記述を追加します。

tsconfig.jsonJSON · 8行
{  "compilerOptions": {    // 他の設定...    "verbatimModuleSyntax": true // 追加    // 他の設定...  }  // 他の設定...}

また、path aliasとexcludeの設定を追加します。

excludeにshadcn/uiのコンポーネントディレクトリを指定することで、TypeScriptのエラーを回避しています。

tsconfig.jsonJSON · 14行
{  "compilerOptions": {    // 他の設定...    "paths": {      "@/*": ["./src/*"],      "@/components/*": ["./src/components/*"],      "@/lib/*": ["./src/lib/*"],      "@/stories/*": ["./src/stories/*"],      "@/styles/*": ["./src/styles/*"]    }  },  // 他の設定...  "exclude": ["node_modules", "src/components/ui/**/*"]}

shadcn/ui

以下のコマンドを実行してshadcn/uiをセットアップします。

ターミナルbash · 1行
npx shadcn@latest init

質問には任意の選択肢を選択します。以下はその例です。

テキストテキスト · 3行
✔ Which style would you like to use? › Default✔ Which color would you like to use as the base color? › Gray✔ Would you like to use CSS variables for theming? … yes

husky + lint-staged

以下のコマンドを実行しhuskyとlint-stagedをインストールし、.husky/pre-commitにコマンドを追加します。

ターミナルbash · 1行
npm i -D husky lint-staged && npx husky init && echo "npx lint-staged" > .husky/pre-commit

package.jsonに以下の記述を追加します。

package.jsonJSON · 4行
{  // 他の設定...  "lint-staged": {}}

この時点で一度コミットしたい場合は、package.jsonのlint-stagedに何も設定していないので、--no-verifyをつけてコミットしてください。

ターミナルbash · 1行
git commit --no-verify -m "コミットメッセージ"

Prettier

以下のコマンドを実行して、Prettierと関連のプラグインをインストールし、設定ファイルを生成します。

ターミナルbash · 1行
npm i -D prettier prettier-plugin-organize-imports && touch .prettierrc && touch .prettierignore

.prettierrcに以下の記述を追加します。

.prettierrcJSON · 28行
{  "printWidth": 80,  "tabWidth": 2,  "useTabs": false,  "semi": true,  "singleQuote": true,  "quoteProps": "as-needed",  "jsxSingleQuote": false,  "trailingComma": "all",  "bracketSpacing": true,  "bracketSameLine": false,  "arrowParens": "always",  "plugins": ["prettier-plugin-organize-imports"],  "overrides": [    {      "files": ["*.html"],      "options": {        "printWidth": 360      }    },    {      "files": ["*.css", "*.scss", "*.sass", "*.less"],      "options": {        "singleQuote": false      }    }  ]}

.prettierignoreに以下の記述を追加します。

.prettierignoreテキスト · 20行
# 依存関係node_modules# ビルド出力とキャッシュ.cache/.next/.nuxt/.astro/build/dist/out/# パッケージマネージャのロックファイルpackage-lock.jsonyarn.lockpnpm-lock.yaml# 特定のJavaScriptモジュールファイル*.cjs*.mjs

以下のコマンドを実行し、VS Codeの設定ファイルを作成します。

ターミナルbash · 1行
mkdir -p .vscode && echo '{}' > .vscode/settings.json

.vscode/settings.jsonに以下の記述を追加します。

.vscode/settings.jsonJSON · 10行
{  "editor.defaultFormatter": "esbenp.prettier-vscode",  "editor.formatOnSave": true,  "editor.formatOnPaste": true,  "editor.codeActionsOnSave": {    "source.addMissingImports.ts": "explicit"  },  "javascript.preferences.importModuleSpecifier": "non-relative",  "typescript.preferences.importModuleSpecifier": "non-relative"}

package.jsonのscriptsに以下の記述を追加します。

package.jsonJSON · 10行
{  // 他の設定...  "scripts": {    // 他の設定...    "lint:prettier": "prettier --check .",    "fix:prettier": "npm run lint:prettier -- --write",    "prepare": "husky"  },  // 他の設定...}

fix:prettierで実行しているコマンドは実質的にprettier --check . --writeになります。

ダブルダッシュ(--)により以降の引数を直接コマンドに渡しています。

npm-run-script | npm Docs⁠(新しいタブで開く)

ESLint

以下のコマンドを実行して、ESLint関連のプラグインをインストールし、.eslintignoreを生成します。

ターミナルbash · 1行
npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-tailwindcss eslint-config-prettier && touch .eslintignore

.eslintrc.jsonを以下の内容に書き換えます。

.eslintrc.jsonJSON · 40行
{  "extends": [    "next/core-web-vitals",    "plugin:@typescript-eslint/recommended",    "plugin:tailwindcss/recommended",    "prettier"  ],  "parser": "@typescript-eslint/parser",  "plugins": ["@typescript-eslint"],  "rules": {    "@typescript-eslint/consistent-type-imports": [      "error",      {        "prefer": "type-imports",        "fixStyle": "separate-type-imports"      }    ],    "@typescript-eslint/no-unused-vars": [      "warn",      {        "vars": "all",        "varsIgnorePattern": "^_",        "args": "after-used",        "argsIgnorePattern": "^_"      }    ],    "object-shorthand": "error",    "tailwindcss/no-custom-classname": "off",    "react/jsx-curly-brace-presence": "error",    "react/self-closing-comp": [      "error",      {        "component": true,        "html": false      }    ],    "@next/next/no-img-element": "off",    "react/no-unescaped-entities": "off"  }}

設定は以下の記事の記述を使用させていただきました。

Next.js 14 + TypeScript + Tailwind + ESLint + Prettier 環境構築手順⁠(新しいタブで開く)

.eslintignoreに以下の記述を追加します。

.eslintignoreテキスト · 33行
# 依存関係node_modules/# ビルド出力とキャッシュ.cache/.next/.nuxt/.astro/build/dist/out/# 静的ファイルpublic/# パッケージマネージャのロックファイルpackage-lock.jsonyarn.lockpnpm-lock.yaml# 設定ファイルvite.config.tsnext.config.jstsconfig.jsontailwind.config.jstailwind.config.ts# 型定義ファイルsrc/env.d.ts# 特定のJavaScriptモジュールファイル*.cjs*.mjs

.vscode/settings.jsonに以下の記述を追加します。

.vscode/settings.jsonJSON · 19行
{  "editor.defaultFormatter": "esbenp.prettier-vscode",  "editor.formatOnSave": true,  "editor.formatOnPaste": true,  "editor.codeActionsOnSave": {    "source.addMissingImports.ts": "explicit",    "source.fixAll.eslint": "explicit" // 追加  },  "javascript.preferences.importModuleSpecifier": "non-relative",  "typescript.preferences.importModuleSpecifier": "non-relative",  // ▽ 追加  "eslint.validate": [    "html",    "javascript",    "javascriptreact",    "typescript",    "typescriptreact"  ]}

package.jsonのscriptsに以下の記述を追加します。

package.jsonJSON · 12行
{  // 他の設定...  "scripts": {    // 他の設定...    "lint:eslint": "eslint .", // 追加    "lint:prettier": "prettier --check .",    "fix:eslint": "npm run lint:eslint -- --fix", // 追加    "fix:prettier": "npm run lint:prettier -- --write",    "prepare": "husky"  },  // 他の設定...}

npm-run-all

コマンド1つでまとめて複数のコマンドを実行できるようにするためにnpm-run-allをインストールします。

ターミナルbash · 1行
npm i -D npm-run-all

package.jsonのscriptsを以下のように変更・追加します。

package.jsonJSON · 15行
{  // 他の設定...  "scripts": {    // 他の設定...    "lint": "next lint", // 削除    "lint": "run-p -l -c --aggregate-output lint:*", // 追加    "lint:eslint": "eslint .",    "lint:prettier": "prettier --check .",    "fix": "run-s fix:prettier fix:eslint", // 追加    "fix:eslint": "npm run lint:eslint -- --fix",    "fix:prettier": "npm run lint:prettier -- --write",    "prepare": "husky"  },  // 他の設定...}
  • run-p

    npm-run-allの並列実行(parallel)

    ※npm-run-all -pの省略

  • -l

    ラベルを付けて出力を表示し、どのタスクからの出力かを明示

    ※--print-labelの省略

  • -c

    エラーが発生しても他のタスクを継続して実行

    ※--continue-on-errorの省略

  • --aggregate-output

    すべてのタスクの出力を集約して表示

  • lint:*

    lint:で始まるすべてのスクリプトを実行

  • run-s

    npm-run-allの逐次実行(sequential)

    ※npm-run-all -sの省略

npm-run-all/docs/npm-run-all.md at master · mysticatea/npm-run-all⁠(新しいタブで開く)

補足

npm-run-allは、2018年11月公開の4.1.5から更新されていません。同じrun-p・run-sコマンドを使える、メンテナンスが続いているフォークのnpm-run-all2があります。

bcomnes/npm-run-all2: A CLI tool to run multiple npm-scripts in parallel or sequential. (Maintenance fork)⁠(新しいタブで開く)

lint-stagedの設定

package.jsonのlint-stagedに以下の記述を追加します。

package.jsonJSON · 12行
{  // 他の設定...  "lint-staged": {    "*.{js,jsx,ts,tsx}": [      "eslint --fix",      "prettier --write"    ],    "*.{json,md,mdx,css,scss,yaml,yml}": [      "prettier --write"    ]  }}

Storybook

以下のコマンドを実行してStorybookのプロジェクトをセットアップします。

ターミナルbash · 1行
npx storybook@latest init

tsconfig.jsonのpath aliasが反映されるように.storybook/main.tsを以下のように変更します。

.storybook/main.tsTypeScript · 27行
import type { StorybookConfig } from '@storybook/nextjs';import path from 'path';const config: StorybookConfig = {  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],  addons: [    '@storybook/addon-onboarding',    '@storybook/addon-links',    '@storybook/addon-essentials',    '@chromatic-com/storybook',    '@storybook/addon-interactions',  ],  framework: {    name: '@storybook/nextjs',    options: {},  },  webpackFinal: async (config) => {    if (config.resolve) {      config.resolve.alias = {        ...config.resolve.alias,        '@': path.resolve(__dirname, '../src'),      };    }    return config;  },};export default config;

そのままだとshadcn/uiのスタイルが適用されないので、.storybook/preview.tsに以下の記述を追加します。

.storybook/preview.tsTypeScript · 15行
import type { Preview } from '@storybook/react';import '@/styles/globals.css'; // 追加const preview: Preview = {  parameters: {    controls: {      matchers: {        color: /(background|color)$/i,        date: /Date$/i,      },    },  },};export default preview;
補足

create-next-appで作った直後は、globals.cssはsrc/appにあります。src/stylesに移していない場合は、import '@/app/globals.css';と書きます。また、main.tsのaddonsの内容は、Storybookのバージョンによって変わります。生成された内容はそのままにして、webpackFinalの部分だけを足してください。

package.jsonのlint-stagedも以下のように修正します。

package.jsonJSON · 12行
{  // 他の設定...  "lint-staged": {    "*.{js,jsx,ts,tsx,stories.js,stories.jsx,stories.ts,stories.tsx}": [      "eslint --fix",      "prettier --write"    ],    "*.{json,md,mdx,css,scss,yaml,yml}": [      "prettier --write"    ]  }}

動作確認

上記の完了後に変更内容をコミットし、コミット前にPrettierやESLintが実行されることを確認してください。

参考・引用

この記事は役に立ちましたか?