14
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Next.js × TypeScript × Tailwind CSS × JestとESLint・Prettier設定のBoilterplate紹介

Last updated at Posted at 2021-09-23

現在開発しているアプリのフロント実装をNext.js × TypeScript・Tailwind CSSでやっています。
今後もしばらくこの構成が鉄板になりそうなので、関連ライブラリのセットアップも含めてボイラープレート化することにしました。

環境

  • React 17.0.2
  • yarn 1.22.11
  • Next.js 11.1.0
  • TypeScript 4.4.2
  • Tailwind 2.2.9
  • ESLint 7.32.0
  • Prettier 2.3.2
  • Jest 27.1.0

##1. Next.jsとTypeScriptでプロジェクトの開始

Next.jsとTailwind CSSのセットでインストールする方法もありますが、TypeScriptとのセットでやった方がTypeScript周りの設定が楽になるのでこちらでいきます。(Tailwind CSSについては後ほど設定していきます。)

npx create-next-app --ts my-app[アプリ名]
#or
yarn create next-app --ts my-app[アプリ名]

参考:

※ちなみに、Tailwind CSSの公式にあるやり方も踏まえ yarn create next-app -e with-tailwindcss —-ts みたいに同時にインストールしてみようとしましたが、最初に記述した方しか適用されておらず同時インストールは無理でした。

ついでにsrcフォルダを作成し配下にファイルを移動

mkdir src
mv  pages src
mv  components src
mkdir src/lib

##2. 絶対パス/パスエイリアスの指定

ts.configの設定

 ※ tsconfig.jsonの変更後はdev serverをリフレッシュしないと反映されないので注意

{
    "compilerOptions": {
        {...}
        "baseUrl": ".",
        "paths": {
            "@components/*": ["components/*"],
            "@styles/*": ["styles/*"],
            "@pages/*": ["pages/*"],
            "@hooks/*": ["hooks/*"]
        }
    {...}
}

こんな感じ

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "baseUrl": ".",
    "paths": {
        "@components/*": ["components/*"],
        "@styles/*": ["styles/*"],
        "@pages/*": ["pages/*"],
        "@hooks/*": ["hooks/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

参考:

この中身についてはこちらの記事が役に立つ

適宜targetやlibなど設定しておく(本題ではないので飛ばします。興味がある方はご自身で調べてみてください。)

##3. Tailwind CSS と JIT Modeの設定 
※注) 1月24日(月)現在はv3のため設定が異なります。
やり方は3つあり、それぞれ簡略化されて設定が楽になっています。
↓詳しくはこちらをご覧ください。
https://tailwindcss.com/docs/installation

これは色々と設定が必要になります。

$ npm install -D tailwindcss@latest postcss@latest autoprefixer@latest postcss-cli
#or
$ yarn add -D tailwindcss@latest postcss@latest autoprefixer@latest postcss-cli

https://tailwindcss.com/docs/guides/nextjs#install-tailwind-via-npm

tailwind.config.tsとpostcss.config.jsファイルの作成をしていきます。

npx tailwindcss init -p

postcss.config.jsファイルは基本的にそのままで大丈夫です。

簡単に中身だけ説明しておくと

module.exports = {
  plugins: {
    tailwindcss: {}, //PostCSSのプラグインとしてTailwind CSSを使用する設定
    autoprefixer: {}, //-webkitなどベンダープレフィックスを自動でつけてくれる(様々なブラウザ対応のため)
  },
};

tailwind.config.tsの中身を設定

JITモードに設定し、不要なCSSを削除するためのpurge設定をする。

purgeとは、ここに設定されているファイル内で使用されているCSSのみをbuild時に使用する最適化手法です。

初期設定は18万行のコードを全て読み込むことになっているため、ファイルサイズが大きくなってしまうのです。

※パス指定はご自身のファイル構造に従ってください。ここが違うとCSSが正しく読み込まれません。

module.exports = {
    mode: 'jit',
    purge: ['./src/pages/**/*.{js,ts,jsx,tsx}', './src/components/**/*.{js,ts,jsx,tsx}'],
    darkMode: false, // or 'media' or 'class'
    theme: {
        extend: {},
    },
    variants: {
        extend: {},
    },
    plugins: [],
};

Tailwind CSSで生成されたCSSを読み込むために styes/Home.module.cssファイルを削除しておきます。

また、styles/global.module.cssはbuild時にtailwind.cssを読み込む際に、動的に反映するファイルとして残しておきましょう。(詳細は後ほど説明します)

そして、styes/tailwind.cssファイルを作成して中身に以下を記述します。

@tailwind base;
@tailwind components;
@tailwind utilities;

もしも@tailwindのルールがないってエラーが出たら

以下の方法で解決

PostCSSのプラグインを導入(VS Codeのみ)

PostCSS Language Support - Visual Studio Marketplace

How to add a @tailwind CSS rule to css checker

詳しくは記事化しました↓

ついでにTailwind CSSの入力補完をしてくれる、Tailwind CSS IntelliSenseも導入しておきましょう。

このままではTailwind CSSの記述を変更してもJITモードでリアルタイムに変更されないので、そのための設定をする必要があります。

package.jsonの設定を加える

{
    ...
    "scripts": {
        "dev": "next dev",
        "build": "next build",
        "start": "next start",
        "lint": "next lint",
        "css:dev": "TAILWIND_MODE=watch postcss src/styles/tailwind.css -o src/styles/globals.css --watch",
        "css:build": "postcss src/styles/tailwind.css -o src/styles/globals.css",
    },
    ...

ちょっとわかりづらいかもしれませんが中身はこうなっています。

TAILWIND_MODE=watch(watchモードにする) 

postcss [対象となるファイル] -o(outputの略)[アウトプット先のファイル]

The css:dev script will run PostCSS in watch mode, and Tailwind will listen for changes in our component classes to build new utilities classes on the go. Once everything is done, we can build the final version of the CSS by running our css:build script.

watchモードとは
ファイルを監視して変更があったらビルドを再実行する機能のこと。watchモードでは基本的にキャッシュが有効になるため、ビルド時間が短くなる。
例えば、pages/index.tsx内のTailwind CSSを監視して、そこに変更があったときにbuildを改めて走らせてくれる様になります。

では、npm run devもしくはyarn devしてlocallhostを立ち上げてください。
Tailwind CSSの記述をしたときにglobals.css(postCSSのファイル)に動的に追記されればOKです。
ブラウザでも動的に変わるか確認しましょう。
変わっていなければ上記の設定の記述に誤りがないか、パスの指定はあっているかなど見直してみてださい。

スクリーンショット 2021-08-31 14.41.28.png
・左側のファイル: src/pages/index.tsx
・右側のファイル:globals.css

尚、追加されたCSSの記述はそのまま残ってしまいますが、build時に使わないファイルは消去してくれるので yarn dev し直すと不要な記述が消えていることが確認できます。

##4. ESLintとPrettierの導入
ESLintの導入
Next.js のバージョン 11 に対応
Next.js では、バージョン 11 から、ESLint がデフォルトで搭載されています。ESLint に関連するインストール済みのパッケージは以下 2 つです。

  "devDependencies": {
    "eslint": "7.32.0",
    "eslint-config-next": "11.1.0",
    ...
    }

Next.js の新規プロジェクト作成時に生成された .eslintrc.json は ESLint の設定ファイルを意味しており、デフォルトで eslint-config-next の設定が適用されています(ルールの詳細は後述)

 // .eslintrc
{
  "extends": ["next", "next/core-web-vitals"]
}

次に拡張機能としてESLintを導入します。

スクリーンショット 2021-08-31 7.49.44.png

VS Code 上でリアルタイムに ESLint で構文解析でき、コードの保守性が高められる様になります。

しかし、ファイル数が多いとき、全てのファイルを VS Code で確認するのは大変なため、対象ファイルを一括で ESLint による構文解析したい場合は、lint コマンドを使用する。

npm run lint
#or
yarn lint

また Next.js にデフォルトで搭載された ESLint では、lint コマンドの対象ディレクトリが 以下 3 つに限定されているそうです。

  • pages
  • lib
  • components

そのためおすすめはsrcディレクトリにpagesを含むソースコードを管理して、lintコマンドオプション —-dir src でsrcディレクトリ配下のファイルが対象になる。

#例)
    src
    ├── pages
    │   ├── _app.tsx
    │   ├── api
    │   └── index.tsx
    ├── components
    │   └── hoge.tsx #任意のディレクトリ・ファイル構成
    └── styles
        ├── Home.module.css
        └── globals.css

次に、package.json の lint コマンドに対し、--dir src を記述してください。

package.json
"scripts": {
      ...
      "lint": "next lint --dir src"
      ...
},

Prettierの導入

チーム開発する際に、コード整形のルールをコードベースで設定することでばらつきを防ぐことができる。

Prettier におけるコード整形のルールを記述する主な方法は、以下 2 つ

  • .prettierrc ファイルを作成し、ルールを記述
  • package.json にルールを記述

省ファイルを意識してpackage.jsonに記述するのがおすすめ

package.json
      "prettier": {
        "trailingComma": "all",// 末尾のカンマあり
        "tabWidth": 2,// tab の長さは半角スペース 2 
        "semi": true,// セミコロンあり
        "singleQuote": true,// シングルクォーテーションに統一
        "jsxSingleQuote": true,//jsx もシングルクォーテーションに統一
        "printWidth": 100 //  行の最大文字数 100
      }

次に、

以下 2 つのパッケージをインストールしましょう。

  • prettier 各ファイルをコマンドで、フォーマットできるようにするため
  • eslint-config-prettier ESLint と Prettier のコード整形がバッティングしないようするため
npm install -D prettier eslint-config-prettier
#or
yarn add -D prettier eslint-config-prettier

さらに.eslintrc.jsonに下記のように設定することでESLintとPrettierのコード整形がバッティングをしない様にできる

{
  "extends": ["next", "next/core-web-vitals", "prettier"]
}

最後に、Prettier でフォーマットするコマンドを package.json に記述しましょう。

補足
--write: フォーマット整形
--ignore-path .gitignore: .gitignore に含まれているファイルはコード整形の対象外
'./**/*.{js,jsx,ts,tsx,json,css}'":対象ファイルの拡張子を指定

package.json
      "scripts": {
        "lint": "next lint --dir src",
        "lint:fix": "eslint src --ext .js,jsx,.ts,.tsx --fix",
        "format": "prettier --write --ignore-path .gitignore './**/*.{js,jsx,ts,tsx,json,css}'"
      }

prettierがCLIで効くか
確認する

npm run format
#or
yarn format

##5. JestとReact Testing Libraryのセットアップ

yarn add -D @testing-library/dom @testing-library/jest-dom @testing-library/react @testing-library/user-event babel-jest jest jest-dom node-mocks-http ts-jest ts-loader

Project folder 直下に".babelrc"ファイルを作成して下記設定を追加

$ touch .babelrc

 {
    "presets": ["next/babel"]
 }

package.json に jest の設定を追記

"jest": {
        "testPathIgnorePatterns": [
            "<rootDir>/.next/",
            "<rootDir>/node_modules/"
        ],
        "moduleNameMapper": {
            "\\.(css)$": "<rootDir>/node_modules/jest-css-modules"
        }
    }

package.jsonに test scriptを追記

 "scripts": {
      ...
      "test": "jest --env=jsdom --verbose"
  },

prettierの設定 : .prettierrcを作成しsettingsでRequire Config + Format On Saveにチェック

$ touch .prettierrc

.prettierrc

.prettierrc
    {
        "singleQuote": true,
        "semi": false
    }

Test動作確認

 __tests__フォルダとHome.test.tsxファイルの作成

Home.test.tsx
/**
 * @jest-environment jsdom
 */

import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import Home from '../pages/index'

it('Should render title text', () => {
  render(<Home />)
  expect(screen.getByText('Next.js!')).toBeInTheDocument()
})

yarn test -> テストがPASSするか確認

PASS  __tests__/Home.test.tsx
  ✓ Should render hello text (20 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.728 s, estimated 2 s

次の様なエラーが出たら、

Hello

などtextのタグにスペースを開けずにテストしたいテキストのみを記述する。
TestingLibraryElementError: Unable to find an element with the text: TailwindCSS. 
This could be because the text is broken up by multiple elements. 
In this case, you can provide a function for your text matcher to make your matcher more flexible.

これで先程のコマンドをもう一度実行して、パスしていれば完了です。

※とりあえず仮のテストなのでテスト内容によって書き換えが必要です

##最後に

これでようやくできました。色々設定が必要ですが、こうしてまとめておくと今後はプロジェクトのセットアップを省力化できるはずです。

また今回の設定はフロントエンド諸学者である私一個人が調べて導入したものであって、全ての人に当てはまるベストプラクティスではないことを念の為お伝えしておきます。

必要に応じてカスタマイズをしてみてください。

自分も、storybookなどまだ試したことはないけれど入れておきたいライブラリがあるので、確認できたら随時更新していきたいと思います。

また上記の設定で、よりベターな選択肢があれば積極的に情報共有してもらえると嬉しいです。

不明点や誤りがある場合も遠慮なく言っていただければ幸いです。

##参考資料

14
12
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?