Next.jsでWebアプリを作るときの環境構築手順メモ

Next.js 14でWebアプリを作るための環境構築をしたときのメモ。

  • WSL2 : Ubuntu 22.04.3 LTS

  • Docker version 24.0.6

  • VS Code 1.85.2 x64

  • Next 14.1.0

VSCodeの改行の設定を、念のためLFにする。

.vscode/settings.json
{
  "files.eol": "\n"
}

VS Codeの拡張機能Dev Containersを使うために、devcontainer.jsonを作成する。

.devcontainer/devcontainer.json
{
  "name": "Next.js",
  "build": {
    "dockerfile": "./Dockerfile",
    "context": ".."
  },
  "appPort": ["3010:3000"],
  "customizations": {
    "vscode": {
      "extensions": [
        "PulkitGangwar.nextjs-snippets",
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "bradlc.vscode-tailwindcss"
      ]
    }
  }
}

Dockerfileを作成する。

.devcontainer/Dockerfile
FROM node:20-slim

EXPOSE 3000

RUN apt-get update -y \
  && DEBIAN_FRONTEND=noninteractive \
  apt-get install -y --no-install-recommends \
  ca-certificates \
  git \
  locales \
  tzdata \
  xsel \
  && update-ca-certificates \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

RUN locale-gen ja_JP.UTF-8 \
  && localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV TZ=Asia/Tokyo \
  LANG=ja_JP.UTF-8 \
  LANGUAGE=ja_JP:jp \
  LC_ALL=ja_JP.UTF-8

RUN npm install -g npm

USER node

VSCodeの拡張機能のうち、必須の拡張機能はdevcontainer.jsonに書く。 必須でないものは、recommendationとしてプロジェクトに追加するため、.vscode/extensions.jsonに記述する。

.vscode/extensions.json
{
  "recommendations": [
    "streetsidesoftware.code-spell-checker",
    "naumovs.color-highlight",
    "igorsbitnev.error-gutters",
    "saikou9901.evilinspector",
    "mhutchie.git-graph",
    "donjayamanne.githistory",
    "oderwat.indent-rainbow",
    "visualstudioexptteam.vscodeintellicode",
    "christian-kohler.path-intellisense",
    "gruntfuggly.todo-tree",
    "shardulm94.trailing-spaces"
  ]
}

VSCodeの拡張機能Dev Containersを使って、Dockerfileをビルドし、Dockerコンテナにアタッチする。

VS Code拡張機能のDev Containers をローカルにインストールする。その後、Ctrl + Shift + Pでコマンドパレットを開き、Dev Containers: Reopen in Containerを実行する。これにより、Dockerfileがビルドされ、VS Codeがコンテナにアタッチされる。

VS Codeの拡張機能のタブで@recommendedと検索すると、.vscode/extensions.jsonに記述した拡張機能が表示される。必要に応じて拡張機能をインストールする。

プロジェクトをgit管理下に置く。

git init

branch名をデフォルトでmainにしていない場合はwarningが出るので、mainにしておく。

git branch -m main

コンテナ内でアプリ作成コマンドをたたく。

npx create-next-app@latest

create-next-appをインストールするか聞かれたらyを入力してインストールする。 いろいろ聞かれるが、project name以外すべてデフォルトにする。project nameは任意の名前にする。

出力結果の例を示す。

設定選択

$ npx create-next-app@latest
Need to install the following packages:
create-next-app@14.1.0
Ok to proceed? (y) y
✔ What is your project named? … next-app
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
Creating a new Next.js app in /workspaces/ff14-tune-finder/next-app.

Using npm.

Initializing project with template: app-tw


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- autoprefixer
- postcss
- tailwindcss
- eslint
- eslint-config-next


added 360 packages, and audited 361 packages in 11s

128 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Initialized a git repository.

Success! Created next-app at /workspaces/ff14-tune-finder/next-app

作成されたアプリディレクトリへ移動し、アプリを起動する。

cd next-app
npm run dev

http://localhost:3010/ にアクセスすると、Next.jsのデフォルトページが表示される。

デフォルトページ

デフォルトのESLintだとTypeScriptのエラーが出ないので修正する。

Next.js ESLint で TypeScript のエラーを表示するようにしたい - かもメモ's image

Next.js ESLint で TypeScript のエラーを表示するようにしたい - かもメモ

1. Next.js はデフォルトでは TypeScript のエラーが `npm run lint` では表示されない 2. ミニマムな TypeScript のエラーを表示させるには `@typescript-eslint/eslint-plugin` をインストールして `.eslintrc.json` にルールを追加する 3. 使用するルールに依っては `.eslintrc.json` に `parserOptions.project` プロパティを作成しプロジェクトの `tsconfig.json` のパスを指定する

必要なパッケージを入れる。

npm i -D @typescript-eslint/eslint-plugin

.eslintrc.jsonを変更する。rulesの部分は必要に応じて変更してよい。

.eslintrc.json
{
  "root": true,
  "extends": ["plugin:@typescript-eslint/recommended", "next/core-web-vitals"],
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "rules": {
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/no-explicit-any": "error",
    "@typescript-eslint/no-unsafe-call": "error",
    "@typescript-eslint/no-unsafe-member-access": "error",
    "@typescript-eslint/no-unsafe-return": "error"
  }
}

変更した.eslintrc.jsonを参照するように、VS Codeの設定を変更する。

.vscode/settings.json
{
  // Linter
  "eslint.workingDirectories": ["./next-app"],
  "editor.codeActionsOnSave": {
    "source.fixAll": "never",
    "source.fixAll.eslint": "explicit"
  }
}

package.jsonのlintコマンドを変更し、.gitignoreの対象ファイルはLint対象外にする。

package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
-   "lint": "next lint"
+   "lint": "next lint --ignore-path .gitignore"
  },

ESLintを実行して動作を確認する。

npm run lint

FormatterとしてPrettierを入れる。パッケージをインストールする。

npm i -D prettier eslint-config-prettier

Prettierの設定ファイル.prettierrcを作る。

.prettierrc
{
  "semi": true,
  "trailingComma": "all",
  "singleQuote": true,
  "printWidth": 80,
  "tabWidth": 2
}

.eslintrc.jsonにPrettierを追加する。必ず最後に追加する。

.eslintrc.json
{
  "root": true,
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "next/core-web-vitals",
+   "prettier"
  ],
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "rules": {
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/no-explicit-any": "error",
    "@typescript-eslint/no-unsafe-call": "error",
    "@typescript-eslint/no-unsafe-member-access": "error",
    "@typescript-eslint/no-unsafe-return": "error"
  }
}

VSCodeの設定に、Prettier関連の設定を追記する。

.vscode/settings.json
{
  // formatter
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.formatOnPaste": true,
  "editor.formatOnType": true
}

package.jsonformatコマンドを追加する。

package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint --ignore-path .gitignore",
+   "format": "prettier --write --ignore-path .gitignore ."
  },

Prettierを実行して動作を確認する。

npm run format

コミット時にnpm run lintnpm run formatを実行し、エラーが出る場合はコミットできないようにする。

まず、huskylint-stagedをインストールする。

npm i -D husky lint-staged

次に、husky-initコマンドを実行する。このコマンドは環境により異なるため、実行するコマンドの詳細はhuskyの公式サイト を参照すること。npmの場合は下記になる。

npx husky-init && npm install
Getting started | 🐶 husky's image

Getting started | 🐶 husky

Git hooks made easy

このとき、.gitディレクトリとpackage.jsonファイルが同じ階層に存在しないため、下記のようなエラーが発生する。

$ npx husky-init && npm install
Need to install the following packages:
husky-init@8.0.0
Ok to proceed? (y) y
husky-init updating package.json
  setting prepare script to command "husky install"
/home/node/.npm/_npx/1ab9c0f68ac2536e/node_modules/husky/lib/index.js:23
        throw new Error(`.git can't be found (see ${url})`);
        ^

Error: .git can't be found (see https://typicode.github.io/husky/#/?id=custom-directory)
    at install (/home/node/.npm/_npx/1ab9c0f68ac2536e/node_modules/husky/lib/index.js:23:15)
    at Object.<anonymous> (/home/node/.npm/_npx/1ab9c0f68ac2536e/node_modules/husky-init/lib/bin.js:16:21)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49

Node.js v20.11.0

このエラーへの対処法は、huskyの公式サイト に書かれているとおりで、npx husky-initによってpackage.jsonに追加されたprepareスクリプトを変更する。

Guide | 🐶 husky's image

Guide | 🐶 husky

Git hooks made easy

たとえば、プロジェクト名がnext-appの場合は下記のように変更する。

package.json
{
  "scripts": {
-   "prepare": "husky install"
+   "prepare": "cd .. && husky install next-app/.husky"
  },
}

変更したら、再度npm i(あるいはnpm install)を実行する。

npm i

成功すると、.huskyディレクトリが生成される。

.huskyディレクトリが生成されたら、自動実行のためのhookを追加する。今回はpre-commitのhookを追加する。

npx husky add .husky/pre-commit "npx lint-staged"

実行すると、.huskyディレクトリに下記のpre_commitファイルが生成される。

.husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

今回は.gitディレクトリとpackage.jsonファイルが同じ階層に存在しないため、下記のように、階層を移動するコマンドを追加する必要がある。

.husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

+ cd next-app  # package.jsonのある階層に移動する

npx lint-staged

ここまでできたら、lint-stagedの設定に移る。Next.jsにおけるlint-stagedの設定は特殊である。詳細はNext.jsの公式サイト を参照すること。

Configuring: ESLint | Next.js's image

Configuring: ESLint | Next.js

Next.js reports ESLint errors and warnings during builds by default. Learn how to opt-out of this behavior here.

要するに、Next.jsにおいてnext lintlint-stagedを共存させる場合は、.lintstagedrc.jsファイルを作成し、そこに設定を記す必要がある。

公式に載っている.lintstagedrc.jsを下記に引用する。

.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}': [buildEslintCommand],
}

上記のように、module.exportsに、適用するファイルと実行するコマンドのペアを記述する。たとえば、自動修正しないlinterとformatterを実行する場合は、下記のようになる。

.lintstagedrc.js
const path = require('path');

const buildLintCommand = (filenames) =>
  `next lint --file ${filenames
    .map((f) => path.relative(process.cwd(), f))
    .join(' --file ')}`;

const buildFormatCommand = (filenames) =>
  `prettier --check --debug-check ${filenames
    .map((f) => path.relative(process.cwd(), f))
    .join(' ')}`;

module.exports = {
  'app/**/*.{js,jsx,ts,tsx}': [buildLintCommand],
  'pages/**/*.{js,jsx,ts,tsx}': [buildLintCommand],
  '*.{js,jsx,ts,tsx,json,css}': [buildFormatCommand],
};

以上までの設定で、コミット時にlinterとformatterが自動で実行され、通らない場合はコミットできなくなる。

コミットメッセージのフォーマットを統一するため、commitlintを入れる。

commitlint - Lint commit messages's image

commitlint - Lint commit messages

Lint commit messages

commitlintとCommitizenを使ってチーム開発におけるコミットメッセージを統一する's image

commitlintとCommitizenを使ってチーム開発におけるコミットメッセージを統一する

まず、commitlintを入れる。コマンドは上記リンク先を参照すること。下記は一例である。

npm install --save-dev @commitlint/{cli,config-conventional}

次に、下記のコマンドを実行してcommitlint.config.jsを作成する。

echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

作成されたcommitlint.config.jsは以下のようになる。

commitlint.config.js
module.exports = { extends: ['@commitlint/config-conventional'] };

以上でcommitlintが動作するようになったので、実行されるか確認する。

npx commitlint --from HEAD~1 --to HEAD --verbose

実行されれば、下記のようなログが出力される。

commitlintの実行結果
$ npx commitlint --from HEAD~1 --to HEAD --verbose
⧗   input: build(git): set up husky and lint-staged pre-commit
✔   found 0 problems, 0 warnings

commitlintが実行できたら、コミット時にcommitlintを自動実行するように設定する。commitlintcommit-msgフックで実行する。下記のコマンドを実行して、huskycommit-msgフックを追加する。

npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'

これにより、.husky/commit-msgファイルが作成される。

.husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no -- commitlint --edit ${1}

.gitディレクトリとpackage.jsonが同一階層にない場合は、下記のように階層を移動するコマンドを追加する必要がある。

.husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

+ cd next-app  # package.jsonのある階層に移動する

npx --no -- commitlint --edit ${1}

これで、コミット時にcommitlintが実行されるようになる。

最後に、commitlintのルールを変更する。commitlintのルールは、commitlint.config.jsにルールを追記することで上書きできる。デフォルトの設定および上書き方法は、下記公式サイトに記述されている。

commitlint - Lint commit messages's image

commitlint - Lint commit messages

Lint commit messages

たとえば、subject-max-length50に変更する場合は、下記のようにルールを追記する。

commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],

+ rules: {
+   'subject-max-length': [2, 'always', 50],
+ },
};
failed to fetch remote resource: Forbidden commitlint の紹介 - Qiita's image

commitlint の紹介 - Qiita

commitlint というツールをご紹介します。http://marionebl.github.io/commitlintcommitlint とは、Git のコミット規約(commit co…

ルールは、{ルール名}: [{レベル:0|1|2}, '{可否:always|never}', {値}]の形式で記述する。レベルは各数値が下記段階に該当する。

  • 0: 無効
  • 1: 警告
  • 2: エラー

オレオレルールを下記に示す。

commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],

  rules: {
    'type-case': [2, 'always', 'lower-case'],
    'scope-case': [2, 'always', 'lower-case'],
    'subject-max-length': [2, 'always', 50],
    'body-full-stop': [2, 'always', '.'],
    'body-leading-blank': [2, 'always'],
    'body-max-line-length': [2, 'always', 72],
    'body-case': [2, 'always', 'sentence-case'],
    'footer-leading-blank': [2, 'always'],
    'footer-max-line-length': [2, 'always', 72],
  },
};

参考文献・URLは適宜記事内に示した。

Licensed under CC BY-NC-SA 4.0
最終更新 Jan 20, 2024
Built with Hugo
テーマ StackJimmy によって設計されています。