Vite + React + SWC + ESLintの環境を整える

投稿日
/
更新日
Vite + React + SWC + ESLintの環境を整える

webpackに比べ高速と評判のViteを用いてReact開発環境を作成しつつ、

ESLintを導入して更にDXを上げたReactの開発環境の作成方法をご紹介します!

検証した環境

1 react 18.2.0
2 vite 4.1.4
3 eslint 8.36.0

node環境の設定

2023/03/11現在、nodeのLTSが18.15.0なのでnodenvを使って固定していきます

# ローカル環境になければインストール
$ nodenv install 18.15.0
 
# v18.15.0を使用する
$ nodenv local 18.15.0
 
# nodeのバージョンを指定出来た事を確認
$ node -v
v18.15.0

Reactの開発環境を用意

Vite + React のプロジェクトを用意します

$ npm create vite
# or
$ yarn create vite

React公式で紹介されているcreate-react-appを用いると

webpackで作られてしまうため注意です!



表示された順に入力・選択していきます


プロジェクト名(後でも変えられるので適当でもOK)

プロジェクト名を入力

frameworkでReactを選択

frameworkでReactを選択

迷いポイント

言語+ビルドツールの選択
  • JavaScript
  • TypeScript
  • JavaScript + SWC
  • TypeScript + SWC

の4つから選択します。



今のご時世だとほぼほぼTypeScriptを選択するプロジェクトが多いと思われるので、下記どちらかを選択するケースが多いはず。

  • TypeScript
  • TypeScript + SWC (多分こっちがおすすめ)


上記2つの違いとしては、それぞれ導入されるViteのプラグインが変わってきます

  • TypeScript・・@vitejs/plugin-react
  • TypeScript + SWC・・@vitejs/plugin-react-swc

プラグインの詳細については公式ページに

プラグイン | Vite



プラグインの違いを比較すると

@vitejs/plugin-react

esbuild と Babel を使用し、小さなパッケージフットプリントで高速な HMR や、Babel 変換パイプラインを使用できる柔軟性を実現します。Babel プラグインを追加しない場合、ビルド時には esbuild のみが使用されます。

  • esbuild + Babel

@vitejs/plugin-react-swc

開発中は Babel を SWC に置き換えます。ビルド時には、プラグインを使用する場合は SWC+esbuild、それ以外は esbuild を使用します。非標準の React 拡張を必要としない大きなプロジェクトでは、コールドスタートやホットモジュールリプレースメント(HMR)が大幅に高速化されます。

  • esbuild + SWC

と読み取れそうです。



SWCはBabelを置き換えるために開発された高速なビルドツールなので、

Babelの文脈でSWCを使って問題なければ TypeScript + SWC を用いるのが良いのかなと感じました!




最後に表示された通りコマンドを実行

cd vite-project
yarn
yarn dev


dev環境が起動します。

yarn dev実行後、ローカルホストが立ち上がった事が分かる


http://localhost:5173/ にアクセスすると

ローカルホストにアクセスするとViteのReact環境が立ち上がる

無事Vite+Reactでアプリケーションが立ち上がりました!🎉


Prettier導入

Prettierを導入します

$ yarn add -D prettier

設定ファイルを追加 (設定内容はお好みで)

.prettierrc
{
  "semi": true,
  "singleQuote": true,
  "bracketSameLine": true,
  "printWidth": 100
}

既存のファイルにPrettierを実行

$ npx prettier --write .

ESLintを導入

本題の1つ、ESLintを導入していきます!


ESLintを対話形式で初期設定

まずESLintのパッケージを追加

$ yarn add -D eslint

ESLintの設定ファイルを作成していきます

Getting Started with ESLint - ESLint - Pluggable JavaScript Linter

$ npm init @eslint/config

initを実行する際にnpmを使いますが

最終的にパッケージをインストール前にnpm・yarn・pnpmのどれでインストールするかを選択出来ます



ここから対話形式で進んでいきます



必要なパッケージのインストール

Need to install the following packages:
  @eslint/create-config@0.4.2
Ok to proceed? (y)

@eslint/create-config が必要だからインストールしていいか?

と聞かれるのでEnterを押してyを実行


プロジェクト内のpackage.jsonに追加されるのではなく、
グローバルに一時的かもですがインストールされているようです。

ESLintの使い方

? How would you like to use ESLint? …
  To check syntax only
  To check syntax and find problems
❯ To check syntax, find problems, and enforce code style

1番下のTo check syntax, find problems, and enforce code styleがおすすめ

構文の解析・問題の発見・コードスタイルの強制の全部入り


「コードスタイルの強制」というのは

この後の項目で出てくる、AirbnbやGoogleが公開しているESLintのコーディングスタイルをextendし、それを守る事になります。


有名所のスタイルガイドに則れるので、基本はコードスタイルの強制を選択して良いかなと思います。



プロジェクトで用いるモジュールについて

? What type of modules does your project use? …
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

ReactなのでJavaScript modulesを選択


  • JavaScript modules・・ES2015のimport/export
  • CommonJS・・CommonJSのrequire

フレームワーク

? Which framework does your project use? ...
❯ React
  Vue.js
  None of these

Reactを選択


TypeScriptの利用有無

? Does your project use TypeScript? › No / Yes

TypeScriptを使うのでYesを選択


コードの実行場所

? Where does your code run? …  (Press <space> to select, <a> to toggle all, <i> to invert selection)
✔ Browser
✔ Node

Browserを選択


どのようにESLintのスタイルを定義するか

? How would you like to define a style for your project? …
❯ Use a popular style guide
  Answer questions about your style

それぞれ以下のようになります

  1. Use a popular style guide(人気のスタイルガイドを使用)
  2. Answer questions about your style(自分で選択する)

有名なスタイルガイドを利用する場合は1、完全に1からカスタムする場合は2.

ですね。


私はUse a popular style guide を選択


利用するスタイルガイド

? Which style guide do you want to follow? …
❯ Standard: https://github.com/standard/eslint-config-standard-with-typescript
  XO: https://github.com/xojs/eslint-config-xo-typescript

なぬ・・以前あったAirbnbがない💦


XOはzero-configで始められるESLintのラッパーとして開発されたライブラリなので、

XOのいい感じのESLintの設定が導入されるという予想。



個人的に馴染みのあるAirbnbを入れたいので、

ここではStandardを選択、後でAirbnbを入れる事にします


設定ファイルのフォーマット

? What format do you want your config file to be in? …
❯ JavaScript
  YAML
  JSON

ESLintの設定ファイル(eslintrc)はJSONファイルで紹介されてる事が多いイメージ、

かつJSON形式とほぼ同じように書けてコメントが出来るJavaScriptを選択


.eslintrc.cjsが作成されます


.eslintrc.cjsを馴染みある.eslintrc.jsにしてeslintを実行するとエラーが起きます

$ npx eslint . --ext .js,.jsx,.ts,.tsx
 
Oops! Something went wrong! :(
 
ESLint: 8.36.0
 
Error [ERR_REQUIRE_ESM]:
require() of ES Module /Users/yuu/src/github.com/yuki-takara/react-vite-sample/.eslintrc.js
from /Users/yuu/src/github.com/yuki-takara/react-vite-sample/node_modules/@eslint/eslintrc/dist/eslintrc.cjs not supported.
 
.eslintrc.js is treated as an ES module file as
it is a .js file whose nearest parent package.json
contains "type": "module" which declares all .js files in that package scope as ES modules.
 
Instead rename .eslintrc.js to end in .cjs,
change the requiring code to use dynamic import() which is available in all CommonJS modules,
or change "type": "module" to "type": "commonjs" in /Users/yuu/src/github.com/yuki-takara/react-vite-sample/package.json
to treat all .js files as CommonJS (using .mjs for all ES modules instead).

なるほど、.cjsである必要があるんですね


インストールされるパッケージの確認

eslint-plugin-react@latest eslint-config-standard-with-typescript@latest @typescript-eslint/eslint-plugin@^5.0.0 eslint@^8.0.1 eslint-plugin-import@^2.25.2 eslint-plugin-n@^15.0.0 eslint-plugin-promise@^6.0.0 typescript@*
? Would you like to install them now? › No / Yes

? Which package manager do you want to use? …
  npm
❯ yarn
  pnpm

ここまでの選択でインストールパッケージの一覧が表示されるのでYESを選択


更にその後、そのインストールを行うパッケージマネージャーを選択出来ます。

私はyarnを使っているのでyarnを選択。



導入したパッケージ、.eslintrc.cjsの確認

インストールされたESLint関連のパッケージは以下

package.json
{
  "name": "vite-project",
  ・・・
  "devDependencies": {
    ・・・
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "eslint": "^8.0.1",
    "eslint-config-standard-with-typescript": "^34.0.0",
    "eslint-plugin-import": "^2.25.2",
    "eslint-plugin-n": "^15.0.0",
    "eslint-plugin-promise": "^6.0.0",
    "eslint-plugin-react": "^7.32.2",
    ・・・
  }
}

.eslintrc.cjsはこのようになりました。

.eslintrc.cjs
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: ['plugin:react/recommended', 'standard-with-typescript'],
  overrides: [],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  plugins: ['react'],
  rules: {},
}

eslint-config-airbnb 導入

eslint-config-airbnb - npm


当初入れたかったAirbnbのESLint設定を入れていきます。



AirbnbのESLint設定公式ページに必要なパッケージが書かれていて

Our default export contains most of our ESLint rules, including ECMAScript 6+ and React. It requires eslint, eslint-plugin-import, eslint-plugin-react, eslint-plugin-react-hooks, and eslint-plugin-jsx-a11y.

  • eslint-plugin-react-hooks
  • eslint-plugin-jsx-a11y

の2つがこの段階だと足りていないので、合わせて追加します。

$ yarn add -D eslint-config-airbnb eslint-plugin-react-hooks eslint-plugin-jsx-a11y

もし必要なパッケージの導入を忘れても

eslint実行した際に警告メッセージが表示されるので気付く事が出来ます

$ npx eslint . --ext .js,.jsx,.ts,.tsx
 
Oops! Something went wrong! :(
 
ESLint: 8.36.0
 
ESLint couldn't find the plugin "eslint-plugin-react-hooks".


合わせて.eslintrc.cjsを更新

.eslintrc.cjs
// 変更前
extends: ['plugin:react/recommended', 'standard-with-typescript'],
 
// 変更後
extends: ['plugin:react/recommended', 'airbnb', 'airbnb/hooks'],

使わなくなったeslint-config-standard-with-typescriptは削除します

$ yarn remove eslint-config-standard-with-typescript



eslintコマンドを実行出来る事が確認できれば、eslint-config-airbnb導入成功です!

(この段階だといっぱいエラーが起きます)
$ npx eslint . --ext .js,.jsx,.ts,.tsx
 
 
/Users/yuu/src/github.com/yuki-takara/react-vite-sample/src/App.tsx
   9:5   error  'React' must be in scope when using JSX     react/react-in-jsx-scope
   9:5   error  JSX not allowed in files with extension '.      react/jsx-filename-extension
・・・


eslint-config-airbnb-typesciprt 導入

eslint-config-airbnb-typescript - npm


Airbnbの設定をTypeScriptにも適用するためのものです!



必要なパッケージをインストール

$ yarn add -D eslint-config-airbnb-typescript @typescript-eslint/parser

.eslintrc.cjsを変更します、2箇所あります

.eslintrc.cjs
// 変更前
extends: ['plugin:react/recommended', 'airbnb', 'airbnb/hooks'],
 
// 変更後
extends: ['plugin:react/recommended', 'airbnb', 'airbnb-typescript', 'airbnb/hooks'],


tsconfigを読み込むようにします

これによって読み込んだtsconfigの設定に準拠してくれるようです

.eslintrc.cjs
// 変更前
parserOptions: {
  ecmaVersion: 'latest',
  sourceType: 'module'
},
 
// 変更後
parserOptions: {
  ecmaVersion: 'latest',
  sourceType: 'module',
  project: './tsconfig.json',
},


eslint-config-prettier 導入

eslint-config-prettier - npm


ここまでの設定のみだと、Prettierの設定とESLintの設定がバッティングしている場合、

  • Prettierを実行 → ESLintにPrettierの自動修正部分を怒られる → 手動で直す → Prettierを実行 → ESLintにPrettierの自動修正部分を怒られる ・・

という無限ループが起きます🫠



これを回避するために「Prettierの設定はESLintで警告しない」という設定を追加します。


パッケージをインストール

$ yarn add -D eslint-config-prettier


.eslintrc.cjsを変更

.eslintrc.cjs
// 変更前
extends: ['plugin:react/recommended', 'airbnb', 'airbnb-typescript', 'airbnb/hooks'],
 
// 変更後
extends: ['plugin:react/recommended', 'airbnb', 'airbnb-typescript', 'airbnb/hooks', 'prettier'],


これで導入前、

例えばPrettierの設定でセミコロンを文末に表示しない設定をし

.prettierrc
{
  "semi": false,
  ・・・
}

ESLintを実行すると以下のように怒られていたのが

$ npx eslint . --ext .js,.jsx,.ts,.tsx
 
1:26  error  Missing semicolon       @typescript-eslint/semi
・・・

怒られなくなります 🙌



eslint-plugin-unicorn 導入

More than 100 powerful ESLint rules
4.3k
366
JavaScript


公式ページ

More than 100 powerful ESLint rules

と書かれているように、ESLintをより強力にするルール集です!


かなり色々なルールが追加され、Lintに対応する時間が大変になる可能性もあるので、

速度を求められるようなプロジェクトは入れない判断をするのもあり、だと思います。




パッケージのインストール

$ yarn add -D eslint-plugin-unicorn

.eslintrc.cjsを変更

.eslintrc.cjs
// 変更前
extends: ['plugin:react/recommended', 'airbnb', 'airbnb-typescript', 'airbnb/hooks', 'prettier'],
 
// 変更後
extends: [
  'plugin:react/recommended',
  'airbnb',
  'airbnb-typescript',
  'airbnb/hooks',
  'plugin:unicorn/recommended',
  'prettier',
],


ESLintを実行すると

$ npx eslint . --ext .js,.jsx,.ts,.tsx
 
6:30  error  Prefer `.querySelector()` over `.getElementById()`  unicorn/prefer-query-selector

のように unicorn/で始まるメッセージが表示されるようになっていれば成功です!



ここまでで.eslint.cjsは以下のようになっています

.eslint.cjs
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'airbnb-typescript',
    'airbnb/hooks',
    'plugin:unicorn/recommended',
    'prettier',
  ],
  overrides: [],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    project: './tsconfig.json',
  },
  plugins: ['react'],
  rules: {},
}


npm-scriptのコマンド追加

npm-scriptsで実行出来るようにしておきます。

"lint": "eslint . --ext .js,.jsx,.ts,.tsx"をpackage.jsonに追加

package.json
{
  ・・・
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
  },
  ・・・
}

これで

$ yarn run lint

でESLintが実行出来るようになります


ESLintの修正(ruleの設定)

エラー内容を修正していきます。

本題とは若干それるので、パパっと書いていきます

unicorn/filename-case

eslint-plugin-unicorn/filename-case.md at main · sindresorhus/eslint-plugin-unicorn


Filename is not in kebab case. Rename it to app.tsx

App.tsxというファイル名をケバブケースにしよう、というエラーです。



Reactの場合、

キャメルケース・パスカルケースでファイル名を記載する事が多いため以下のルールを追加します

.eslintrc.cjs
rules: {
  'unicorn/filename-case': [
    'error',
    {
      cases: {
        kebabCase: true,
        pascalCase: true,
      },
    },
  ],
},

react/react-in-jsx-scope

eslint-plugin-react/react-in-jsx-scope.md at master · jsx-eslint/eslint-plugin-react


'React' must be in scope when using JSX

JSXのファイルでimport React from 'react'; を記載しないとこちらのエラーが起きます。


しかし React v17以降はこの記載をしないても問題なくなったためこのルールは無視します

.eslintrc.cjs
rules: {
  ・・・
  'react/react-in-jsx-scope': 'off',
},

react/jsx-no-target-blank

eslint-plugin-react/jsx-no-target-blank.md at master · jsx-eslint/eslint-plugin-react


Using target="_blank" without rel="noreferrer" (which implies rel="noopener") is a security risk in older browsers: see https://mathiasbynens.github.io/rel-noopener/#recommendations

長い文章ですが、要は「target=_"blank" を設定しているリンクは rel="noreferrer" を設定していないとセキュリティ上の問題があるよ」という内容です。


そのため素直にaタグの修正します

// 修正前
<a href="https://vitejs.dev" target="_blank">
</a>
 
// 修正後
<a href="https://vitejs.dev" target="_blank" rel="noreferrer">
</a>

react/button-has-type

eslint-plugin-react/button-has-type.md at master · jsx-eslint/eslint-plugin-react


Missing an explicit type attribute for button

ボタンには必ずtypeを設定しよう、というエラーです。


デフォルトのtype=“button”を設定します

// 修正前
<button onClick={() => setCount((count) => count + 1)}>count is {count}</button>
 
// 修正後
<button onClick={() => setCount((count) => count + 1)} type="button">
  count is {count}
</button>

@typescript-eslint/no-shadow

typescript-eslint/no-shadow.md at main · typescript-eslint/typescript-eslint


'count' is already declared in the upper scope on line 6 column 10

6行目で既にcountという変数を使用しているのに、useStateのsetCount()内で同じ変数名を使用してエラーになっています


どちらかの変数名を変更すれば解決ですね、今回はsetCount内の変数名を変更します

// 修正前
<button onClick={() => setCount((count) => count + 1)} type="button">
  count is {count}
</button>
 
// 修正後
<button onClick={() => setCount((previousCount) => previousCount + 1)} type="button">
  count is {count}
</button>

unicorn/prefer-query-selector

eslint-plugin-unicorn/prefer-query-selector.md at main · sindresorhus/eslint-plugin-unicorn


Prefer.querySelector() over .getElementById()

getElementByIdgetElementsByClassNameは使わずにquerySelectorを使おう、というエラーです


// 修正前
ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
 
// 修正後
ReactDOM.createRoot(document.querySelector('#root') as HTMLElement)

unicorn/prevent-abbreviations

eslint-plugin-unicorn/prevent-abbreviations.md at main · sindresorhus/eslint-plugin-unicorn


The filename vite-env.d.ts should be named vite-environment.d.ts. A more descriptive name will do too

envやprev、といった短縮された変数やファイル名は使わずに、environmentやpreviousと正式名を記載しよう、というエラーです。



なるほどなぁ、と思う内容なものの、とはいえ.envなど普段から一般的に使っているファイル名でもあるため env という単語は使えていい気がする 🤔



ここではESLintのルールを設定する事にします。

allowListに設定した単語はエラーにならなくなります

.eslintrc.cjs
rules: {
  ・・・
  'unicorn/prevent-abbreviations': [
    'error',
    {
      allowList: {
        env: true,
      },
    },
  ],
},

vite.config.tsのParsing error

Parsing error: ESLint was configured to run on `<tsconfigRootDir>/vite.config.ts`
using `parserOptions.project`: /users/yuu/src/github.com/yuki-takara/react-vite-sample/tsconfig.json

However, that TSConfig does not include this file. Either:
- Change ESLint's list of included files to not include this file
- Change that TSConfig to include this file
- Create a new TSConfig that includes this file and include it in your parserOptions.project

ESLintが<tsconfigRootDir>/vite.config.tsというファイルを使用して構成されているが、対応するTSConfigにそのファイルが含まれていないため、エラーが発生しています。


vite.config.tsを対象から外せばいいのでESLintの ignorePatterns を用いて除外します

.eslintrc.cjs
ignorePatterns: ['vite.config.ts'],


これでオールグリーンになりました!

$ yarn run lint
yarn run v1.22.19
$ eslint . --ext .js,.jsx,.ts,.tsx
  Done in 1.56s.

最終的な状態

主要ファイルはそれぞれ最終的に以下のようになりました!


package.json

package.json
{
  "name": "vite-project",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.27",
    "@types/react-dom": "^18.0.10",
    "@typescript-eslint/eslint-plugin": "^5.55.0",
    "@typescript-eslint/parser": "^5.55.0",
    "@vitejs/plugin-react-swc": "^3.0.0",
    "eslint": "^8.0.1",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-config-airbnb-typescript": "^17.0.0",
    "eslint-config-prettier": "^8.7.0",
    "eslint-plugin-import": "^2.25.2",
    "eslint-plugin-jsx-a11y": "^6.7.1",
    "eslint-plugin-n": "^15.0.0",
    "eslint-plugin-promise": "^6.0.0",
    "eslint-plugin-react": "^7.32.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-unicorn": "^46.0.0",
    "prettier": "^2.8.4",
    "typescript": "*",
    "vite": "^4.1.0"
  }
}

.eslintrc.cjs

.eslintrc.cjs
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'airbnb-typescript',
    'airbnb/hooks',
    'plugin:unicorn/recommended',
    'prettier',
  ],
  overrides: [],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    project: './tsconfig.json',
  },
  plugins: ['react'],
  rules: {
    'unicorn/filename-case': [
      'error',
      {
        cases: {
          kebabCase: true,
          pascalCase: true,
        },
      },
    ],
    'react/react-in-jsx-scope': 'off',
    'unicorn/prevent-abbreviations': [
      'error',
      {
        allowList: {
          env: true,
        },
      },
    ],
  },
  ignorePatterns: ['vite.config.ts'],
};
プロフィール画像
Yuki Takara
都内でフリーランスのエンジニアをやってます。フロントとアプリ開発メインに幅広くやってます。