14
17

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.

React × TypeScript × Vite× ESLint × Prettier × Jest × GitHub Actionsな環境を構築した

Last updated at Posted at 2022-05-08

はじめに

Clean Architecture  達人に学ぶソフトウェアの構造と設計を読んだので、これを参考にテスタブルなReactプロジェクトを作ろうと思いました。
ディレクトリ構成について考えがまとまり、いざ作ろう!となった段階で、開発環境の構築で苦労してしまいました。
備忘録的な感じで、まとめておきます。

目次

  • 環境構築の手順
    • React, TypeScript, Viteでのアプリケーション作成
    • ESLint, Prettierのセットアップ
    • Jestのセットアップ
    • GitHub Actionsのセットアップ

環境構築の手順

React, TypeScript, Viteでのアプリケーション作成

以下のコマンドを実行するだけで、簡単にプロジェクトが作成できます。

$ yarn create vite my-react-ts-app --template react-ts

参考

ESLint, Prettierのセットアップ

次に、ESLintとPrettierのセットアップをしていきます。

ESLint

まずはESLintのセットアップからです。最初に以下のコマンドを実行します。

$ yarn add eslint --dev
$ yarn create @eslint/config

すると、質問がいくつか出てくるので、以下のように答えます。

✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ What format do you want your config file to be in? · JavaScript
The config that you've selected requires the following dependencies:

eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
✔ Would you like to install them now? · No

すると以下のESLint用設定ファイルが作成されます。

.eslintrc.js
module.exports = {
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended",
        "plugin:@typescript-eslint/recommended"
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "react",
        "@typescript-eslint"
    ],
    "rules": {
    }
}

nodeの環境でも実行するので以下の変更を加えてください。

   env: {
     browser: true,
     es2021: true,
+    node: true
   },

パッケージマネージャに yarn を使う想定で書いています。以下のコマンドを実行してください。(実は質問の中で npm を使ってinstallしますか?という質問が存在します。もし npm を使っている場合は、そこでyesを選択すると、以下のコマンドは実行しなくても大丈夫です。 )

$ yarn add --save-dev eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest

これで一通りのESLintの設定は終わりです。

今回はここで、ReactやReact hooksに対するESLint設定も加えておきましょう。

$ yarn add --dev eslint-plugin-react-hooks

.eslintrc.js に以下の変更を加えてください。

-  plugins: ['react', '@typescript-eslint'],
+  plugins: ['react', 'react-hooks', '@typescript-eslint'],
   rules: {
+    'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
+    'react-hooks/exhaustive-deps': 'warn', // Checks effect dependencies
+    'react/jsx-key': [
+     'error',
+     {checkFragmentShorthand: true, warnOnDuplicates: true},
+   ],

この設定を入れることで、Reactでのアプリ作成中に気にしなければいけないルールをESLintが検知してくれるようになります。
ルールに関しては、ドキュメントを添付するので見てみてください!

参考↓

Prettier

次にPrettierの設定をしていきます。

$ yarn add --dev --exact prettier
$ echo {}> .prettierrc.json
$ touch .prettierignore

Prettierによってコード整形しなくて良いファイルは .prettierignore に記述しておきましょう。

.prettierignore
# Ignore artifacts:
build
coverage

# Ignore all HTML files:
*.html

また、ESLintとPrettierのルール同士が競合してお互いの動作を邪魔することがあります。その競合を抑えるために、 eslint-config-prettier をinstallして、 .eslintrc.js に変更を加えます。

$ yarn add --dev eslint-config-prettier
     'plugin:react/recommended',
     'plugin:@typescript-eslint/recommended',
     'plugin:promise/recommended',
+    'prettier',
   ],

ではコードの整形を行ってみましょう。

$ yarn prettier --write .

コードが全てのファイルで一定のルールに従って、統一できたかと思います。個人開発用のプロジェクトだったとしても、統一しておくと読みやすいため、Prettierの設定を入れることをお勧めします。

参考

おまけ

husky , lint-staged による自動ESLintチェックの設定もついでにご紹介します。以下のコマンドを実行してください。

$ npx mrm@2 lint-staged

そして、package.json に変更を加えます。

  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
+   "lint": "eslint .",
~~
     "vite": "^2.9.5"
+  },
+  "lint-staged": {
+    "*.{js,ts,tsx}": "yarn lint"
   }
 }

これで、commit時に勝手にESLintによる静的チェックが入るようになります。もしルールに沿っていなければ、勝手にチェックしてくれるので、知らないうちにバグが混入していた、ということを防げる可能性が上がりました。

参考

Jestのセットアップ

次はJestのセットアップです。後少しです。頑張りましょう!
まずは以下のコマンドを実行して、必要なパッケージをインストールしましょう。

$ yarn add --dev jest @types/jest ts-jest ts-node

※ 注意
jest, ts-jestのメジャーバージョンを揃える必要があります。筆者が試した時は、28がまだリリースされて間もない、ということもあり、27で揃えました。

次に、設定を行います。以下のコマンドを実行してください。

$ jest --init

すると以下のような質問が表示されるので、答えてください。

✔ Would you like to use Jest when running "test" script in "package.json"? … yes
✔ Would you like to use Typescript for the configuration file? … yes
✔ Choose the test environment that will be used for testing › node
✔ Do you want Jest to add coverage reports? … no
✔ Which provider should be used to instrument code for coverage? › v8
✔ Automatically clear mock calls, instances, contexts and results before every test? … yes

すると、 jest.config.ts が出来上がります。少し設定を書き換えます。

jest.config.ts

import {InitialOptions} from '@jest/types/build/Config';

const config: InitialOptions = {
  clearMocks: true,
  // An object that configures minimum threshold enforcement for coverage results
  coverageThreshold: {
    global: {
      statements: 100,
    },
  },
  // A list of paths to directories that Jest should use to search for files in
  roots: ['<rootDir>/src'],

  // The glob patterns Jest uses to detect test files
  testMatch: [
    '**/__tests__/**/*.+(ts|tsx|js)',
    '**/?(*.)+(spec|test).+(ts|tsx|js)',
  ],

  // A map from regular expressions to paths to transformers
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
};

export default config;

まずデフォルトで作成される jest.config.ts は型が指定されていないため、設定ファイルに変なプロパティが紛れ込む可能性があります。なので、 InitialOptions で型を指定してあげましょう。
また、今回は C0 = 100% を基準とするため、 coverageThreshold を設定しています。
それ以外は、基本的に TypeScript Deep Dive を参考にします。

設定はこれで完了です。
最後に、簡単なテストの実行してみましょう。

src/foo.ts
export const sum
  = (...a: number[]) =>
    a.reduce((acc, val) => acc + val, 0);
src/foo.test.ts
import { sum } from './foo';

test('basic', () => {
  expect(sum()).toBe(0);
});

test('basic again', () => {
  expect(sum(1, 2)).toBe(3);
});
$ yarn test

これでテストが実行され、完了します。

※ 注意
jest --init のコマンド実行時に package.json に自動でscriptに "test": "jest" が追加されているはずです。ただし、追加されていない場合は、追加してから上記のコマンドを叩いてみてください。

次に、Reactのテストを行いたい場合の環境を作っていきます。必要なモジュールをインストールしていきます。

$ yarn add --dev @testing-library/react @testing-library/jest-dom

実際のテストは書きません(別記事で書きたいと思います)が、テストを行う際は以下のように作ります。

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

import React from 'react';
import {render, screen} from '@testing-library/react';
import '@testing-library/jest-dom';

describe('テストの内容', () => {
~~~
});

順に説明していきます。

/**
 * @jest-environment jsdom
 */

テストに使用する環境をブラウザ環境にする、という宣言です。デフォルトではNode.js環境で行うため、Reactのコンポーネントやhooksのテストを行う場合には、テストの最上部にこちらの宣言が必要になります。

import React from 'react';
import {render, screen} from '@testing-library/react';

Reactのテストに必要なモジュールをimportします。 renderscreen などの @testing-library/react からimportできるものは必要に応じて、importしてください。

import '@testing-library/jest-dom';

toHaveTextContent などマッチャーの拡張を行いたい場合は、上記が必要になります。 @testing-library/jest-dom をimportすることによって使用できるようになるマッチャーは、

  • toBeDisabled
  • toBeInTheDocument
  • toHaveTextContent

などです。詳しくはドキュメントでご確認いただければと思います。

参考

GitHub Actionsのセットアップ

ようやく最後の段階にきました!GitHub Actionsのセットアップを行います。
まず、CIで実行したいコマンドを定義しましょう。

     "dev": "vite",
     "build": "tsc && vite build",
     "preview": "vite preview",
+    "lint": "eslint .",
+    "check": "prettier --check .",

次に設定ファイルを作成します。

$ mkdir -p .github/workflows/
$ touch .github/workflows/on-pull-request.yml

設定を記述していきます。

.github/workflows/on-pull-request.yml
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: On pull request

on:
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [12.x, 14.x, 16.x]
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
      - name: Get yarn cache directory path
        id: yarn-cache-dir-path
        run: echo "::set-output name=dir::$(yarn cache dir)"

      - uses: actions/cache@v3
        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
        with:
          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-
      - name: Install Dependencies
        run: yarn install --prefer-offline
      - name: Run eslint
        run: yarn lint
      - name: Run prettier
        run: yarn run check
      - name: Run jest
        uses: ArtiomTr/jest-coverage-report-action@v2
        with:
          package-manager: yarn
          skip-step: install
          test-script: yarn test

CIでESLintやPrettierによるチェックを行います。
また、テストを実行していますが、実行するだけではなく、coverageも同時にPRへ出力されるようにしたいと思います。
今回は ArtiomTr/jest-coverage-report-action@v2 を使用して、上記を実現します。依存関係のインストールから、テストの実行までをこちらで行ってくれるのですが、依存関係はすでに前段階でインストール済みなので、 skip-step: install というオプションを使います。他にもいくつも設定ができますので、ドキュメントを参照してみて下さいね。以下にURLを添付しておきます。

参考

まとめ

普段はすでに作成されたプロジェクトを使って開発しているため、こういった環境構築は少し慣れない部分もあり、てこずりました。
本来の目的であったテスタブルなReactプロジェクト作成及びテストコードの指針作成に向けて、今回作成したリポジトリで引き続き開発を続けていきます。
次は、テスタブルなReactプロジェクト及びテストコードについて記事を書けたらと思います。

14
17
0

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
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?