DockerでNext.js+TailwindCSS開発環境をチーム開発を意識して構築してみた
概要
Dockerを利用して、Next.js, Tailwind CSSの最低限の開発環境を最速で構築したいと思います!
チーム開発を意識して、リンター、フォーマッター、Gitで管理した際の他メンバーが実行するコマンドも記述しています。
1. Dockerfile, docker-compose.ymlの作成
概要プロジェクトのルートディレクトリに、dockerfile, docker-compose.ymlを作成します。
FROM node:16.14.2-alpine
WORKDIR /app/
CMD [ "yarn", "build" ]
version: "3"
services:
  front:
    build: .
    tty: true
    ports:
      - "3000:3000" # 開発用
      - "4000:4000" # 本番用
    volumes:
      - ./app/myapp:/app # ./app/{プロジェクト名}:/app
    command: yarn dev
Dockerfileでは、ECSなどを利用することを想定して、本番環境が構築できるコマンドを記述します。この段階では、Dockerfileは未完成であり、「10. package.json修正」で完成させます。
ベースイメージは、現段階で安定版のnode:16.14.2を利用します。
イメージを軽量にするため、alpine型を利用します。
docker-compose.ymlでは、開発環境時のコマンドを記述します。
command(CMD)は、Dockerfileとdocker-compose.ymlで異なったコマンドを記述しています(yarn devとyarn build)が、最後に出てきたコマンドで上書きされて実行されます。
そのため、開発時に実行するdocker-compose up -dコマンドでは、docker-compose.ymlに記述されたcommandが後述となり上書きされます。つまり、開発時はyarn devコマンドの方が実行されます。
CMD ["yarn", "build"]
CMD ["yarn", "start"]
CMD ["yarn", "dev"]
# この場合後述のCMD ["yarn", "dev"]のみが適用されて他のコマンドは無視される
docker-compose.ymlのvolumesは適宜変更してください。
2. コンテナ起動、create next app導入
# イメージビルド
$ docker-compose build
# 一時的にコンテナ作成、コンテナに入る(以降コンテナ内シェル
$ docker-compose run --rm front sh
# create next appを実行
$ yarn create next-app --typescript
# プロジェクト名入力
✔ What is your project named? … myapp
プロジェクト名を入力してエンター(ここでは、myappにする)。docker-compose.ymlのvolumeのところで記載したディレクトリ名と合わせると良いです。
完了すると、app/内に以下のようなファイル群がインストールされます。
app/myapp/
├── .eslintrc
├── .gitignore
├── README.md
├── next-env.d.ts
├── next.config.js
├── node_modules
├── package.json
├── pages/
├── public/
├── styles/
├── tsconfig.json
└── yarn.lock
3. Tailwind CSS導入
2.の状態の続きでシェルはコンテナ内です。
# プロジェクトディレクトリに移動
$ cd myapp
# TailwindCSSにまつわるパッケージ導入
$ yarn add -D tailwindcss postcss autoprefixer cssnano
# 初期化
$ yarn tailwindcss init -p
initコマンドを実行するとtailwind.config.js、postcss.config.jsが生成されます。
各導入パッケージについて
- postcss
- CSS構文を便利なプラグインなどを通してより良いCSSへと変換してくれる、JavaScriptで書いたツール
- TailwindCSS, autoprefixer, cssnanoは、postCSSのプライグインとして利用する
 
- tailwindcss
- Tailwind CSS本体
- PostCSSのプラグインとして利用する
 
- autoprefixer
- ベンダープリフィックスを自動的につけてくれるプラグイン
 
- cssnano
- ビルド語のCSSファイルを圧縮してくれるプラグイン
 
4. postCSS, TailwindCSSの設定ファイル作成
3.で作成された設定ファイルを修正していきます。
module.exports = {
  plugins: {  // 利用するプラグインを設定
    tailwindcss: {}, // tailwindCSSの利用プラグイン
    autoprefixer: {}, // ベンダープレフィックス自動生成プラグイン
    cssnano: {}, // ビルドファイルを圧縮プラグイン
  },
};
module.exports = {
  content: [
    // class属性を含む全てのファイルを指定する必要がある(jsx,htmlなど)
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
postcss.config.jsではpostcssで利用するプラグインを記述します。
tailwind.config.jsでは、TailwindCSSの設定ファイルを記述します。
TailwindCSSv3.xでは、v2.xと設定ファイルの構成が異なっています。詳しくは公式ページをご覧ください。
3.xではJust-in-Time (JIT)が正式エンジンになり、purgeCSSが廃止されました。また、variantもすべてのユーティリティで自動的に利用できるようになっているので、記述が不要になっています。
なので、より簡素で使いやすくなっています:)
5. CSSファイルの設定
app/myapp/styles/globals.cssの先頭に以下のコマンドを追加します。
@tailwind base;
@tailwind components;
@tailwind utilities;
globals.cssはapp/myapp/pages/_app.tsxで読み込まれいるので、pages内ファイルでTailwindCSSが使えるようになります。
6. サーバーの起動
# ctrl+D で一時的に作成したコンテナのshellを抜け、新しいコンテナ起動
$ docker-compose up -d 
コンテナ内でyarn devが実行されます。
http://localhost:3000 にアクセスし、以下の画面が出たらOK。

また、app/myapp/pages/index.tsxのJSXでTailwindCSSの構文を書いて、適用されていることを確認。なお、ホットリロードは適用されているので、コードを保存するだけで、適用されていると思います。
return (
  <main>
    <h1 className=" text-4xl font-bold  text-red-700">ヘッダー</h1>
  </main>
)
7. リンター、フォーマッターの設定
7.1 パッケージ導入
必要なパッケージを追加します。なお、ESLintはcreate next appに内包されています。
# $ docker-compose exec front sh でコンテナに入る
# 必要なパッケージ導入
$ yarn add -D prettier eslint-plugin-tailwindcss eslint-config-prettier
各種パッケージ説明
- prettier
- フォーマッター本体
 
- eslint-plugin-tailwindcss
- tailwindにおける構文エラー、class名の並び順を指摘してくれるESLintのプラグイン
 
- eslint-config-prettier
- prettierとESLintが競合しないようにするためのプラグイン
 
7.2 eslint設定ファイルの修正
{
  "extends": [
    "next",
    "next/core-web-vitals",
    "prettier", // prettierとeslintとの衝突回避
    "plugin:import/recommended",
    "plugin:import/typescript",
    "plugin:import/warnings",
    "plugin:tailwindcss/recommended" // class名を整形したりする
  ],
  "rules": {
    // import の順番をルール化
    "import/order": [
      "error",
      {
        "alphabetize": {
          "order": "asc"
        }
      }
    ]
  }
}
importの並び順をルールとして規定しています。詳しくは、eslint-plugin-importを参照ください。
7.3 コマンド設定
フォーマットするためのコマンドなどを指定します。ついでに本番用確認用サーバーのポートは4000に設定しておきます。開発ローカルサーバーはデフォルトでポートは3000です。
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start -p 4000",
    "lint": "next lint",
    "format": "prettier --write --ignore-path .gitignore './**/*.{js,jsx,ts,tsx,json,css}'"
  },
8. 各種コマンド実行
以上の設定でコンテナ内で以下のコマンドで各種コマンドを実行することができます。
# リンター
$ yarn lint
# フォーマッター
$ yarn format
# 開発サーバー起動(ホットリロードが使える)
$ yarn dev
# ビルド
$ yarn build
# 本番用サーバー起動(まずビルドする必要がある)
$ yarn build && yarn start
以上で、ある程度使える環境が整ったのではないでしょうか。
9. 他メンバーが環境構築する場合
以上で初回環境開発が終わりで、できたソースコードをGitHubなどで管理すると思います。
その時、他のプロジェクトメンバーが環境構築する際のコマンドを示します。
# クローン
$ git clone https://github.com/***/project.git
# 移動
$ cd ./project
# イメージビルド
$ docker-compose build
# パッケージインストール(初回または、新たにパッケージが導入された時のみ)
$ docker-compose run --rm front yarn install --frozen-lockfile
# コンテナ起動
$ docker-compose up -d
http://localhost:3000 にアクセスできたら成功です!
10. package.json修正
ECS用に修正します。初回時はpackage.jsonがなかったため記述できませんでしたが、パッケージをインストールするコマンドを記述します。
こうすることで、Dockerfileのみあれば、ベースのnodeの環境上に必要パッケージを導入し、ビルドファイルを構築することができます。
FROM node:16.14.2-alpine
WORKDIR /app/
# パッケージインストールのためのコマンド追加
COPY ./app/package.json ./app/yarn.lock ./
RUN yarn install --frozen-lockfile
# 全ファイルをコピー
COPY ./app/ ./
CMD [ "yarn", "build" ]
おまけ(エディターvscodeの設定)
VSCodeを利用している人限定ですが、今回の環境で便利な拡張機能を紹介します。
- 
ESLint
- リアルタイムでESLintで検出されたエラーを表示してくれます
- また保存と同時に修正してくる設定もできます
 
- 
Prettier
- 保存と同時にフォーマッターをかけてくれます
 
- 
PostCSS Language Support
- cssファイル内でpostcss構文を対応
 
- 
Tailwind CSS IntelliSense
- Tailwind構文をサジェストしてくれます
 
また、上記の拡張機能の設定をプロジェクトメンバーに共有することもできます。
プロジェクトのルートディレクトリに.vscode/settings.jsonを作成し、ルールを以下のように書くだけです。
そうすると、このプロジェクト内だけでルールが適用されるのでとても便利です。
{
  // デフォルトのフォーマッタを prettier に設定
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  // ファイル保存時、prettier による自動フォーマット
  "editor.formatOnSave": true,
  // ファイル保存時、ESLint による自動フォーマット
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  }
}
最後に
間違い、できない等あればご指摘いただけたらと思います:)
参考





Discussion
自分も似たような環境を作成しようとしているのですが、dockerでNext.jsの環境構築するメリットはなんなのでしょうか?
nodeのバージョンなどが別でも環境構築ができると言う点なのでしょうか。ただその場合は、普段開発している際にも、コンテナ内のnodeを使用してパッケージなどのインストールをしないといけないのではと考えているのですが、そこはローカルにダウンロードされてるnodeで開発を行なっていくイメージなのでしょうか。
docker初心者なので、的外れな質問でしたらすみません😓
そうですね。。。
Next.jsに限らず、複数のプロジェクトを同時で進行していた際、効果を発揮すると思っています。
例えば、プロジェクトAではnode12.x, プロジェクトBでは16.xを利用する時を考えます。
ローカルのnodeでは、一つバージョンしか選択できず、いちいち切り替えたりする作業が発生し、大変です。
そこで、Dockerを利用すれば、ローカルのバージョンを気にすることなく、同時に2つのプロジェクトの環境を各nodeのバージョンに応じて立ち上げることができます。(プロジェクトAは12.x、プロジェクトBは16.,x)
なので、いちいち切り替え作業をすることなる同時開発ができます。
また、ECSなどのサービスを利用できるのもメリットかなって思います。
こちらは、ローカルのnodeではなく、コンテナ内のnodeを利用して、インストールすべきですね:)
ご丁寧な返信ありがとうございます!!
なるほど、2つのプロジェクト環境を利用するときなどに活躍するんですね🤔
こちらは、例えば以下のようなコマンドで可能だと思うのですが、開発の際はどのように使用しているでしょうか?
docker exec -it sample-react-container sh -c "npm install {package}"これだと、長くて😓
自分の場合は、docker-composeコマンドを利用します。
しかしそれでも長いのでエイリアスでもっと簡単にしてます!
macであれば以下のファイルを追加します。
これで以下のように使えます。
また、vscodeであれば、remote containersという拡張機能を利用すれば、コマンド打たずに、コンテナを起動、コンテナ内のコードを編集できます。
拡張機能を貼っておきます。
詳しくは、自分で調べてみてください!