Reactのモダン環境(Typescript+Vite+tailwind+jest+cypress+storybook+etc)
こだわりの環境を作るまでにやったこと
目標
下記ライブラリーを入れて設定する。
- React(v18)
- Typescript
- Vite
- eslint, prettier
- tailwindcss, scss
- jest, testing-liblary
- cypress
- storybook
- その他、便利そうなもの
- lodash
- axios
- react-icons
- swr
- headressUI
- husky
- hygen
ベースを持ってきて使いやすくする(React, Typescript, Vite)
今回は、vite のテンプレートを使う
yarn create vite vitest-react-sample --template react-ts
インストールされたのはこんな感じ。
{
"name": "vitest-react-sample",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.24",
"@types/react-dom": "^18.0.8",
"@vitejs/plugin-react": "^2.2.0",
"typescript": "^4.6.4",
"vite": "^3.2.3"
}
}
お好みで設定
nodeのバージョンを指定したいので下記を追加
"engines": {
"node": "16.16.0"
},
vite.config.tsを修正し、.envを読み込めるようにする
vite.config.tsを修正。
build時に吐き出すファイルの場所の変更と、index.htmlでenvを読み込めるように変更。
この設定を追加しとくことで、index.htmlのファイルでENVの中の変数でVITE_から始まるものを使えるようになる。
GA4なんかの設定を書く時に便利だったりするので入れておく。
参考
// @ts-nocheck
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig(({ mode }) => {
return {
plugins: [react(), htmlPlugin(loadEnv(mode, '.'))],
publicDir: 'public',
build: {
outDir: './public/build',
},
}
})
/**
* Replace env variables in index.html
* @see https://github.com/vitejs/vite/issues/3105#issuecomment-939703781
* @example `%VITE_MY_ENV%`
* @see https://vitejs.dev/guide/api-plugin.html#transformindexhtml
*/
function htmlPlugin(env: ReturnType<typeof loadEnv>) {
return {
name: 'html-transform',
transformIndexHtml: {
enforce: 'pre' as const,
transform: (html: string): string => html.replace(/%(.*?)%/g, (match, p1) => env[p1] ?? match),
},
}
}
.envを追加
VITE_TITLE=Template
index.htmlのtitleタグを変更
<!-- <title>Vite + React + TS</title> -->
<title>%VITE_TITLE%</title>
ここまで確認
yarn install
yarn dev
http://localhost:5173/に接続し、画面が表示されるのを確認
eslint, prettierの設定追加
eslintを入れる
npx eslint --init
対話形式で進むので質問に答えるだけでOK
参考
prettierを入れる
yarn add -D prettier eslint-config-prettier
設定ファイルを変更する
お好みで、.prettiercと.eslintrc.ejsを編集してください。
参考までに自分の設定載せときます
eslint
// eslint-disable-next-line no-undef
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:react/recommended',
'prettier',
],
overrides: [],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['react', '@typescript-eslint'],
rules: {
'react/react-in-jsx-scope': 'off',
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }],
},
}
prettierc
{
"trailingComma": "all",
"tabWidth": 4,
"semi": false,
"singleQuote": true,
"jsxSingleQuote": true,
"useTabs": true,
"printWidth": 160
}
vscode自動保存設定
保存時自動prettierするためにsettings.jsonに下記追加
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
最後にpackage.jsonを修正しコマンド追加
eslint,prettierが機能するか確認します。
scriptに下記追加
"format": "prettier --write --ignore-path .gitignore './**/*.{js,ts,tsx,css}'",
"eslint": "eslint --ignore-path .gitignore './**/*.{js,ts,tsx,css}'",
"eslintfix": "eslint --fix --ignore-path .gitignore './**/*.{js,ts,tsx,css}'"
実行
yarn format
yarn eslint
tailwindとscssを入れて設定する
まずはtailwindからインストールしていく
yarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
# classNameを自動で並び替えるプラグイン。もし必要ならば入れる
yarn add -D prettier-plugin-tailwindcss
上記で、インストールと2つのconfigファイルが生成される
設定ファイルの変更
- tailwind.config.cjsの変更
// content: [],
content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'],
- index.cssの修正
内容を下記に置き換える
@tailwind base;
@tailwind components;
@tailwind utilities;
ファイルに下記のような一文を追加して、tailwindが機能しているか確認する。
<p className="text-blue-300 bg-red-600">Hello Vite + React!</p>
テスト環境追加
jestのインストール
yarn add -D jest @types/jest ts-jest jest-environment-jsdom
Testing Libraryのインストール
yarn add -D @testing-library/react @testing-library/jest-dom @testing-library/user-event @testing-library/react-hooks
configファイルで設定を書いていく
お好みで書いていただければと思います
参考までに自分の描いたものを載せてときます
- jest.config.jsを作成する
- jest.setup.tsを作成する
- package.jsonに追記する
module.exports = {
preset: 'ts-jest/presets/js-with-babel-esm',
testEnvironment: 'jest-environment-jsdom',
setupFilesAfterEnv: ['./jest.setup.ts'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
transformIgnorePatterns: ['node_modules/(?!@mui/material)/'],
}
import '@testing-library/jest-dom'
"test": "jest --config ./jest.config.cjs"
導入されてるか確認
下記2ファイルをsrc配下においてテスト成功するかどうか確認する
import { render, screen } from '@testing-library/react'
import { MyComponent } from './MyComponent'
test('「Hello Test」が描画されている', () => {
render(<MyComponent />)
screen.debug()
expect(screen.getByText('Hello Test')).toBeInTheDocument()
})
export function MyComponent() {
const title = 'Hello Test'
return (
<div>
<p>{title}</p>
</div>
)
}
cypress導入
インストールする
yarn add -D cypress
package.jsonにコマンドを追加して、cy:open を実行。
"cy:open": "cypress open",
"cy:test": "cypress run",
フォルダが作成されて、実行できることが確認できる
作られたcypress.config.tsを書き換え
configファイルはお好みで変更してください。
import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:5173',
supportFile: './cypress/support/e2e.ts',
defaultCommandTimeout: 20000,
},
video: false,
})
動作確認
テストファイルを作成し実行してみる
/cypress/e2e/test.cy.ts
/// <reference types="cypress" />
context('起動テスト', () => {
it('起動テスト', () => {
cy.visit('/')
})
})
yarn cy:test を実行
cypressのファイルアップロードするテストがある場合はこの記事のようにライブラリーを入れると良い
storybook導入
ストーリーブックを入れる
コマンド一発で簡単に導入できる
npx sb init
main.jsの書き換えとstorybookをtailwindに対応させる
コマンド実行後 .storybook というフォルダが出来上がっており、その中のmain.cjsとpreview.cjsをお好みに合わせて変えていく
参考
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)', '../components/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
framework: '@storybook/react',
core: {
builder: '@storybook/builder-vite',
},
features: {
storyStoreV7: true,
},
}
import '../src/index.scss'
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
import '../src/index.scss' この一文でtailwindを読んでいるので注意
この記事に出てくるアドオンがなくても動いているが、必要な場合もあるかもしれない
動作確認
ストーリーの作成
src/components/ にMyComponent.tsx と MyComponent.stories.tsx を作る
動作確認で使うためreact-router-domをインストール
yarn add -D react-router-dom
export function MyComponent() {
const title = 'Hello Test'
return (
<div>
<p className='font-bold'>{title}</p>
</div>
)
}
import { type ComponentMeta, type ComponentStoryObj } from '@storybook/react'
import { MyComponent } from './myFunc'
import { MemoryRouter } from 'react-router'
import React from 'react'
type T = typeof MyComponent
type Meta = ComponentMeta<T>
type Story = ComponentStoryObj<T>
export default {
title: 'component/AnchorButton',
component: MyComponent,
args: {},
decorators: [(Story) => <MemoryRouter>{Story()}</MemoryRouter>],
} as Meta
export const Default: Story = {}
yarn storybook を実行、localhost:6006に繋いで確認
その他必要そうなものも入れとく
yarn add -D lodash axios swr @headlessui/react husky hygen
yarn add -D react-router-dom #これはストーリーブックのとこでも描いたので外してますが一緒にinstallしてOKです
便利ツールである、hygen や husky についてはそのうち記事を作成する予定
Discussion