🔥

DockerでNext.js+TailwindCSS開発環境をチーム開発を意識して構築してみた

2022/04/10に公開
4

概要

Dockerを利用して、Next.js, Tailwind CSSの最低限の開発環境を最速で構築したいと思います!
チーム開発を意識して、リンター、フォーマッター、Gitで管理した際の他メンバーが実行するコマンドも記述しています。

1. Dockerfile, docker-compose.ymlの作成

概要プロジェクトのルートディレクトリに、dockerfile, docker-compose.ymlを作成します。

Dockerfile
FROM node:16.14.2-alpine
WORKDIR /app/

CMD [ "yarn", "build" ]
docker-compose.yml
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)は、Dockerfiledocker-compose.ymlで異なったコマンドを記述しています(yarn devyarn build)が、最後に出てきたコマンドで上書きされて実行されます。
そのため、開発時に実行するdocker-compose up -dコマンドでは、docker-compose.ymlに記述されたcommandが後述となり上書きされます。つまり、開発時はyarn devコマンドの方が実行されます。

Dockerfile
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.jspostcss.config.jsが生成されます。

各導入パッケージについて

  • postcss
    • CSS構文を便利なプラグインなどを通してより良いCSSへと変換してくれる、JavaScriptで書いたツール
    • TailwindCSS, autoprefixer, cssnanoは、postCSSのプライグインとして利用する
  • tailwindcss
    • Tailwind CSS本体
    • PostCSSのプラグインとして利用する
  • autoprefixer
    • ベンダープリフィックスを自動的につけてくれるプラグイン
  • cssnano
    • ビルド語のCSSファイルを圧縮してくれるプラグイン

4. postCSS, TailwindCSSの設定ファイル作成

3.で作成された設定ファイルを修正していきます。

postcss.config.js
module.exports = {
  plugins: {  // 利用するプラグインを設定
    tailwindcss: {}, // tailwindCSSの利用プラグイン
    autoprefixer: {}, // ベンダープレフィックス自動生成プラグイン
    cssnano: {}, // ビルドファイルを圧縮プラグイン
  },
};
tailwind.config.js
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の先頭に以下のコマンドを追加します。

app/myapp/styles/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

globals.cssapp/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の構文を書いて、適用されていることを確認。なお、ホットリロードは適用されているので、コードを保存するだけで、適用されていると思います。

index.tsx
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設定ファイルの修正

.eslintrc.json
{
  "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です。

package.json
  "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の環境上に必要パッケージを導入し、ビルドファイルを構築することができます。

Dockerfile
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を作成し、ルールを以下のように書くだけです。
そうすると、このプロジェクト内だけでルールが適用されるのでとても便利です。

.vscode/settings.json
{
  // デフォルトのフォーマッタを prettier に設定
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  // ファイル保存時、prettier による自動フォーマット
  "editor.formatOnSave": true,
  // ファイル保存時、ESLint による自動フォーマット
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  }
}

最後に

間違い、できない等あればご指摘いただけたらと思います:)

参考

https://tailwindcss.com/docs/guides/nextjs

https://fwywd.com/tech/next-eslint-prettier

https://nextjs.org/docs/api-reference/create-next-app

https://github.com/francoismassart/eslint-plugin-tailwindcss

GitHubで編集を提案

Discussion

nickynicky

自分も似たような環境を作成しようとしているのですが、dockerでNext.jsの環境構築するメリットはなんなのでしょうか?
nodeのバージョンなどが別でも環境構築ができると言う点なのでしょうか。ただその場合は、普段開発している際にも、コンテナ内のnodeを使用してパッケージなどのインストールをしないといけないのではと考えているのですが、そこはローカルにダウンロードされてるnodeで開発を行なっていくイメージなのでしょうか。
docker初心者なので、的外れな質問でしたらすみません😓

nerusannerusan

そうですね。。。
Next.jsに限らず、複数のプロジェクトを同時で進行していた際、効果を発揮すると思っています。
例えば、プロジェクトAではnode12.x, プロジェクトBでは16.xを利用する時を考えます。
ローカルのnodeでは、一つバージョンしか選択できず、いちいち切り替えたりする作業が発生し、大変です。
そこで、Dockerを利用すれば、ローカルのバージョンを気にすることなく、同時に2つのプロジェクトの環境を各nodeのバージョンに応じて立ち上げることができます。(プロジェクトAは12.x、プロジェクトBは16.,x)
なので、いちいち切り替え作業をすることなる同時開発ができます。

また、ECSなどのサービスを利用できるのもメリットかなって思います。

コンテナ内のnodeを使用してパッケージなどのインストールをしないといけないのではと考えているのですが、そこはローカルにダウンロードされてるnodeで開発を行なっていくイメージなのでしょうか。

こちらは、ローカルのnodeではなく、コンテナ内のnodeを利用して、インストールすべきですね:)

nickynicky

ご丁寧な返信ありがとうございます!!
なるほど、2つのプロジェクト環境を利用するときなどに活躍するんですね🤔

こちらは、ローカルのnodeではなく、コンテナ内のnodeを利用して、インストールすべきですね:)

こちらは、例えば以下のようなコマンドで可能だと思うのですが、開発の際はどのように使用しているでしょうか?
docker exec -it sample-react-container sh -c "npm install {package}"
これだと、長くて😓

nerusannerusan

自分の場合は、docker-composeコマンドを利用します。

# コンテナ入るコマンド
$ docker-compose exec {service名} sh

# コンテナ内
$ npm i {package}

しかしそれでも長いのでエイリアスでもっと簡単にしてます!
macであれば以下のファイルを追加します。

# ~/.zshrc
# エイリアス登録
alias dc='docker-compose'   # docker-compose をdcで実行できる
alias dce='docker-compose exec'  # docker-compose exec をdceで実行できる

これで以下のように使えます。

$ dce {service名} sh
$ npm i {パッケージ} 

また、vscodeであれば、remote containersという拡張機能を利用すれば、コマンド打たずに、コンテナを起動、コンテナ内のコードを編集できます。
拡張機能を貼っておきます。

https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers

詳しくは、自分で調べてみてください!