Vite + React の環境構築
Next.jsには慣れてきたけど、素のReactで開発ってほとんどしたこと無いのと、Webpack触りたくないvueの本で知ったviteがReactとかでも使えるらしい&わりと評判良さそうなので触ってみつつ、GitHubにテンプレートリポジトリを用意するのを目標にしてみる。
以下参考資料(特に一番上の記事を大いに参考にさせてもらいました
とりあえず yarn create vite
する
$ yarn create vite
yarn create v1.22.17
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Installed "create-vite@2.6.6" with binaries:
- create-vite
- cva
✔ Project name: … react-template
✔ Select a framework: › react
✔ Select a variant: › react-ts
Scaffolding project in /Users/kk6/Products/react-template...
Done. Now run:
cd react-template
yarn
yarn dev
✨ Done in 218.24s.
Volta の pin
コマンドで node と yarn のバージョンを固定
$ volta pin node
success: pinned node@16.13.0 (with npm@8.1.0) in package.json
$ volta pin yarn
success: pinned yarn@1.22.17 in package.json
すると、package.json
に以下の内容が追記される。
"volta": {
"node": "16.13.0",
"yarn": "1.22.17"
}
eslint をセットアップする。npx に相当する yarn のコマンドは yarn2 から使えるようになるらしい。どうせまだ yarn install
する前だし、とりあえず npx eslint --init
でセットアップして、最後の選択肢 Would you like to install them now with npm?
も Yes にしてインストールしてしまおう。
→ npx eslint --init
✔ How would you like to use ESLint? · style
✔ 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
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · airbnb
✔ What format do you want your config file to be in? · JavaScript
Checking peerDependencies of eslint-config-airbnb@latest
Local ESLint installation not found.
The config that you've selected requires the following dependencies:
eslint-plugin-react@^7.21.5 @typescript-eslint/eslint-plugin@latest eslint-config-airbnb@latest eslint@^5.16.0 || ^6.8.0 || ^7.2.0 eslint-plugin-import@^2.22.1 eslint-plugin-jsx-a11y@^6.4.1 eslint-plugin-react-hooks@^4 || ^3 || ^2.3.0 || ^1.7.0 @typescript-eslint/parser@latest
✔ Would you like to install them now with npm? · No / Yes
Installing eslint-plugin-react@^7.21.5, @typescript-eslint/eslint-plugin@latest, eslint-config-airbnb@latest, eslint@^5.16.0 || ^6.8.0 || ^7.2.0, eslint-plugin-import@^2.22.1, eslint-plugin-jsx-a11y@^6.4.1, eslint-plugin-react-hooks@^4 || ^3 || ^2.3.0 || ^1.7.0, @typescript-eslint/parser@latest
added 307 packages, and audited 308 packages in 12s
69 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Successfully created .eslintrc.js file in /Users/kk6/ghq/github.com/kk6/react-template
ESLint was installed locally. We recommend using this local copy instead of your globally-installed copy.
で、package-lock.json
を削除してから yarn install
して yarn.lock
を生成する。
$ rm package-lock.json
$ yarn install
yarn install v1.22.17
warning package.json: No license field
info No lockfile found.
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
warning react-template@0.0.0: No license field
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Saved lockfile.
✨ Done in 38.73s.
init時点の .eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'plugin:react/recommended',
'airbnb',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 13,
sourceType: 'module',
},
plugins: [
'react',
'@typescript-eslint',
],
rules: {
},
};
package.json
に lint
コマンドを追記
"scripts": {
...
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
},
現時点での実行結果(長いので重複していて削除してよさそうな行は省略)
$ yarn lint
yarn run v1.22.17
warning package.json: No license field
$ eslint . --ext .js,.jsx,.ts,.tsx
src/App.tsx
1:33 error Missing semicolon semi
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 '.tsx' react/jsx-filename-extension
14:58 error 'count' is already declared in the upper scope on line 6 column 10 no-shadow
15:23 error `{count}` must be placed on a new line react/jsx-one-expression-per-line
19:16 error `code` must be placed on a new line react/jsx-one-expression-per-line
19:36 error ` and save to test HMR updates. ` must be placed on a new line react/jsx-one-expression-per-line
src/main.tsx
1:8 error 'React' was used before it was defined no-use-before-define
1:26 error Missing semicolon semi
4:17 error Unable to resolve path to module './App' import/no-unresolved
4:17 error Missing file extension for "./App" import/extensions
7:3 error JSX not allowed in files with extension '.tsx' react/jsx-filename-extension
10:34 error Missing trailing comma comma-dangle
vite.config.ts
1:1 error 'vite' should be listed in the project's dependencies, not devDependencies import/no-extraneous-dependencies
1:36 error Missing semicolon semi
2:1 error '@vitejs/plugin-react' should be listed in the project's dependencies, not devDependencies import/no-extraneous-dependencies
6:21 error Missing trailing comma comma-dangle
✖ 38 problems (38 errors, 0 warnings)
19 errors and 0 warnings potentially fixable with the `--fix` option.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
とりあえずこの時点で eslint の fix コマンドを追加して実行してみる
"scripts": {
...
- "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
+ "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
+ "lint:fix": "yarn lint --fix"
},
結果(一部省略)
$ yarn lint:fix
...
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 '.tsx' react/jsx-filename-extension
14:58 error 'count' is already declared in the upper scope on line 6 column 10 no-shadow
src/main.tsx
1:8 error 'React' was used before it was defined no-use-before-define
4:17 error Unable to resolve path to module './App' import/no-unresolved
4:17 error Missing file extension for "./App" import/extensions
7:3 error JSX not allowed in files with extension '.tsx' react/jsx-filename-extension
vite.config.ts
1:1 error 'vite' should be listed in the project's dependencies, not devDependencies import/no-extraneous-dependencies
2:1 error '@vitejs/plugin-react' should be listed in the project's dependencies, not devDependencies import/no-extraneous-dependencies
✖ 19 problems (19 errors, 0 warnings)
error Missing file extension for "./App" import/extensions
は以下を .eslintrc.js
に追記すると解消される。(plugin:import/typescript
のほうだけでもいいのかもだけど、セットで設定してる人が多かった)
extends: [
'plugin:react/recommended',
'airbnb',
+ 'plugin:import/recommended',
+ 'plugin:import/typescript',
],
先にルールを追加したほうが良さそう。
まず、hooks関係のルールを追加してくれるairbnb/hooks
を追加する。
extends: [
'plugin:react/recommended',
'airbnb',
+ 'airbnb/hooks',
'plugin:import/recommended',
'plugin:import/typescript',
]
追加前後で yarn eslint --print-config .eslintrc.js
した結果同士でdiffをとったものが以下。
},
"plugins": [
"jsx-a11y",
+ "react-hooks",
"import",
"@typescript-eslint",
"react"
...
"import/no-duplicates": [
"warn"
],
+ "react-hooks/rules-of-hooks": [
+ "error"
+ ],
+ "react-hooks/exhaustive-deps": [
+ "error"
+ ],
"jsx-a11y/anchor-has-content": [
"error",
{
ちなみに、ここからさらに plugin:react-hooks/recommended
を追加してみたが、print-config
の結果が変わらなかったのでこっちは必要無いらしい。
Typescript関連のルール追加。
extends: [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'airbnb',
'airbnb/hooks',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:import/recommended',
'plugin:import/typescript',
]
print-config
の差分は長いので今回は省く。
ちなみに plugin:@typescript-eslint/recommended-requiring-type-checking
を追加した時点で You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.
って怒られる。なので parserOptions.project
を設定してやる。
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 13,
sourceType: 'module',
+ tsconfigRootDir: __dirname,
+ project: ['./tsconfig.json'],
},
そして、この時点でeslintを実行するとvite.config.ts
でlintエラーになりはじめる。
vite.config.ts
0:0 error Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: vite.config.ts.
The file must be included in at least one of the projects provided
これはとりあえずルールをどうにかするよりも .eslintignore
で対処したほうが良さそう。
build/
public/
**/node_modules/
*.config.js
*.config.ts
*.local
.*
ルールを追加。
rules: {
+ 'import/extensions': [
+ 'error',
+ {
+ js: 'never',
+ jsx: 'never',
+ ts: 'never',
+ tsx: 'never',
+ },
+ ],
+ 'react/jsx-filename-extension': [
+ 'error',
+ {
+ extensions: ['.jsx', '.tsx'],
+ }
+ ],
+ 'react/react-in-jsx-scope': 'off',
+ 'no-use-before-define': 'off',
+ '@typescript-eslint/no-use-before-define': ['error'],
+ 'react/jsx-one-expression-per-line': 'off',
},
import/extensions
これは js/jsx/ts/tsx
なファイルをimportするときに拡張子が無くても良いようにするもの。これで Missing file extension "tsx" for "./App" import/extensions
が解消される。
react/jsx-filename-extension
.tsx
にJSXを書いても良いようにする。これで JSX not allowed in files with extension '.tsx' react/jsx-filename-extension
が解消。
react/react-in-jsx-scope
React16まではJSXから変換後のjsで React
を使用するので、JSXの時点では使わなくても import React from 'react'
を書いておかないといけなかったらしい。しかしもはやimportの必要はないのでこのルールは無効化する。これで 'React' must be in scope when using JSX react/react-in-jsx-scope
が解消。
no-use-before-define と @typescript-eslint/no-use-before-define
以下のように、React
を使っていてもimport React from 'react';
でエラーが出ている
error 'React' was used before it was defined no-use-before-define
import React from 'react';
...
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'),
);
こちらの記事 によると、no-use-before-define
をoffにし、@typescript-eslint/no-use-before-define
を設定してやるとのこと。
react/jsx-one-expression-per-line
例えば以下
count is: {count}
これをoffにしてなくて eslint --fix
すると、このように修正される。
count is:
{' '}
{count}
流石にこれはoffでいいと思う。
ひとまずルールは以上。
最後に残ったlintエラー
src/App.tsx
14:58 error 'count' is already declared in the upper scope on line 6 column 10 no-shadow
これは直してやればいいだけ。
- <button type="button" onClick={() => setCount((count) => count + 1)}>
+ <button type="button" onClick={() => setCount(count + 1)}>
これでlintエラーは全て解消。
Prettierをインストール
$ yarn add -D prettier eslint-config-prettier
.eslintrc.js
に以下追記。
extends: [
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"airbnb",
"airbnb/hooks",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:import/recommended",
"plugin:import/typescript",
+ "prettier",
],
.prettierrc.json
を作成。拡張子はprettierの公式ドキュメントにならってjsonにしてみた。今はとりあえずこれだけでいいと思う(基本的にデフォルト値任せで良さそう)
{
"singleQuote": true
}
ignoreはとりあえず公式ドキュメントの通りで。
# Ignore artifacts:
build
coverage
npm script 追加。
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"serve": "vite preview",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "yarn lint --fix",
+ "lint:format": "prettier --write './**/*.{js,jsx,ts,tsx,css,md,json}'"
},
いい加減 warning package.json: No license field
直さないとね
"volta": {
"node": "16.13.0",
"yarn": "1.22.17"
},
+ "license": "MIT"
}
yarn dev
したときに以下のようなメッセージが出てる
[BABEL] Note: The code generator has deoptimised the styling of /Users/kk6/ghq/github.com/kk6/react-template/node_modules/.vite/react-dom.js?v=921532a8 as it exceeds the max of 500KB.
Sourcemap for "/Users/kk6/ghq/github.com/kk6/react-template/node_modules/.vite/react.js" points to missing source files
Sourcemap for "/Users/kk6/ghq/github.com/kk6/react-template/node_modules/.vite/react_jsx-dev-runtime.js" points to missing source files
Sourcemap for "/Users/kk6/ghq/github.com/kk6/react-template/node_modules/.vite/react-dom.js" points to missing source files
今の所、@vitejs/plugin-react
のバージョンを1.0.5に固定して問題が修正されるのを待つしか無いらしい。