はじめに
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のプロジェクトを作成します。
npx create-next-app@latest <プロジェクト名>質問にはすべてそのままで回答します。
✔ 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 (@/*)? … Notsconfig.json
お好みですが、以下の記述を追加します。
{ "compilerOptions": { // 他の設定... "verbatimModuleSyntax": true // 追加 // 他の設定... } // 他の設定...}また、path aliasとexcludeの設定を追加します。
excludeにshadcn/uiのコンポーネントディレクトリを指定することで、TypeScriptのエラーを回避しています。
{ "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をセットアップします。
npx shadcn@latest init質問には任意の選択肢を選択します。以下はその例です。
✔ 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? … yeshusky + lint-staged
以下のコマンドを実行しhuskyとlint-stagedをインストールし、.husky/pre-commitにコマンドを追加します。
npm i -D husky lint-staged && npx husky init && echo "npx lint-staged" > .husky/pre-commitpackage.jsonに以下の記述を追加します。
{ // 他の設定... "lint-staged": {}}この時点で一度コミットしたい場合は、package.jsonのlint-stagedに何も設定していないので、--no-verifyをつけてコミットしてください。
git commit --no-verify -m "コミットメッセージ"Prettier
以下のコマンドを実行して、Prettierと関連のプラグインをインストールし、設定ファイルを生成します。
npm i -D prettier prettier-plugin-organize-imports && touch .prettierrc && touch .prettierignore.prettierrcに以下の記述を追加します。
{ "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に以下の記述を追加します。
# 依存関係node_modules# ビルド出力とキャッシュ.cache/.next/.nuxt/.astro/build/dist/out/# パッケージマネージャのロックファイルpackage-lock.jsonyarn.lockpnpm-lock.yaml# 特定のJavaScriptモジュールファイル*.cjs*.mjs以下のコマンドを実行し、VS Codeの設定ファイルを作成します。
mkdir -p .vscode && echo '{}' > .vscode/settings.json.vscode/settings.jsonに以下の記述を追加します。
{ "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に以下の記述を追加します。
{ // 他の設定... "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を生成します。
npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-tailwindcss eslint-config-prettier && touch .eslintignore.eslintrc.jsonを以下の内容に書き換えます。
{ "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に以下の記述を追加します。
# 依存関係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に以下の記述を追加します。
{ "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に以下の記述を追加します。
{ // 他の設定... "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をインストールします。
npm i -D npm-run-allpackage.jsonのscriptsを以下のように変更・追加します。
{ // 他の設定... "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-pnpm-run-allの並列実行(parallel)
※
npm-run-all -pの省略-lラベルを付けて出力を表示し、どのタスクからの出力かを明示
※
--print-labelの省略-cエラーが発生しても他のタスクを継続して実行
※
--continue-on-errorの省略--aggregate-outputすべてのタスクの出力を集約して表示
lint:*lint:で始まるすべてのスクリプトを実行run-snpm-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があります。
lint-stagedの設定
package.jsonのlint-stagedに以下の記述を追加します。
{ // 他の設定... "lint-staged": { "*.{js,jsx,ts,tsx}": [ "eslint --fix", "prettier --write" ], "*.{json,md,mdx,css,scss,yaml,yml}": [ "prettier --write" ] }}Storybook
以下のコマンドを実行してStorybookのプロジェクトをセットアップします。
npx storybook@latest inittsconfig.jsonのpath aliasが反映されるように.storybook/main.tsを以下のように変更します。
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に以下の記述を追加します。
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も以下のように修正します。
{ // 他の設定... "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が実行されることを確認してください。
参考・引用
- Next.js 14 + TypeScript + Tailwind + ESLint + Prettier 環境構築手順(新しいタブで開く)
- 【2024/01最新】husky + lint-staged でコミット前にlintを強制する方法(新しいタブで開く)
この記事は役に立ちましたか?