Create React App(TypeScript) + SWC + MUI v5 の環境構築
はじめに
Create React App(TypeScript) + SWC + MUI v5 のSPA環境を構築したフローを記事として記述しています。
利用フレームワーク
本記事で利用するフレームワークの公式サイトを以下に記載します。
-
Create React App
- React アプリケーションの開発環境構築
-
SWC
- Jestのトランスパイルを高速にしてくれるツール
-
MUI
- React UI Library
対象読者
ローカル開発環境でnode.js versionを指定して開発環境を構築できる方向けの記事になります。
利用技術
執筆者のローカル開発環境の各パッケージのバージョンは以下です。
- Mac:
10.15.7
- nodevnv:
1.4.0
- node:
14.17.0
- npm:
8.5.2
- yarn:
1.22.10
ローカル開発環境の準備
ローカル開発環境のnode versionを 14系にしました。
14系にした理由として、執筆者がこのアプリケーションをホスティングする環境を vercel
or Firebse Hosting
の利用を予定していたため、各サービスのドキュメントに記載されたランタイムバージョンを合わせました。
参考文献
- vercel 公式
- Firebse
ローカル開発環境のnode versionを 14系にする
$ node -v
14.17.0
$ npm -v
8.5.2
$ yarn -v
1.22.10
各開発環境のパッケージのバージョンが確認できたので実際にアプリケーションのパッケージをインストールしていこうと思います。
Create React App(Typescript) のインストール
適当な作業ディレクトにて以下コマンドを実行します。
参考文献
$ yarn create react-app project-name --template typescript
インストール実行
Happy hacking!
✨ Done in xx.xxs.
$ cd project-name && yarn start
ブラウザのhttp://localhost:3000
でReactアプリケーションが立ち上がればインストールは完了です。
Lintの設定
つぎにLintの設定をしたいと思います。
$ npx eslint --init
? How would you like to use ESLint? …
❯ To check syntax and find problems
? What type of modules does your project use? …
❯ JavaScript modules (import/export)
? Which framework does your project use? …
❯ React
? Does your project use TypeScript?
Yes
? Where does your code run? …
✔ Browser
✔ Node
? What format do you want your config file to be in? …
❯ JavaScript # ここはお好みでいいと思います
? Would you like to install them now with npm?
Yes
.eslintrc.js
がプロジェクトディレクトリのルートに出力されます。
module.exports = {
"env": {
"browser": true,
"es2021": true,
"node": 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": {
}
}
Prettier のインストール
$ yarn add -D prettier eslint-config-prettier
prettierの設定ファイルを作成します。
$ touch prettier.config.js
設定内容はプロジェクト等によってお好みに記述してみてください。
module.exports = {
printWidth: 80,
tabWidth: 2,
singleQuote: true,
trailingComma: 'none',
semi: false,
parser: 'typescript'
}
.eslintrc.js
の更新します。
module.exports = {
...
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'prettier' // <追記
],
...
};
eslintのプラグインをインストール
- eslint-import-resolver-typescript
- eslint-plugin-react-hooks
$ yarn add -D eslint-import-resolver-typescript eslint-plugin-react-hooks
module.exports = {
...
// settingsに追記
settings: {
'import/resolver': {
typescript: {
project: './tsconfig.json'
}
}
},
plugins: [
'react',
'@typescript-eslint',
'react-hooks' // 追記
],
...
};
ルールの設定をします。
module.exports = {
...
// ルールの設定これはプロジェクト等で話し合って設定がいいと思います
rules: {
// Enable
quotes: ['warn', 'single'],
'no-extra-semi': 'warn',
'@typescript-eslint/no-unused-vars': ['error'],
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
// Disable
'no-unused-vars': 'off',
'react/react-in-jsx-scope': 'off',
'@typescript-eslint/no-empty-function': 'off'
}
...
};
package.jsonの修正
{
...
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"lint:eslint": "eslint --fix src/**/*.{ts,tsx}", // < 追記
"eject": "react-scripts eject" // 削除
},
...
}
動作確認を以下で実行してみます。
$ yarn lint:eslint
@swc/jestのインストール
SWC is an extensible Rust-based platform for the next generation of fast developer tools. It's used by tools like Next.js, Parcel, and Deno, as well as companies like Vercel, ByteDance, Tencent, Shopify, and more.
SWCはSpeedy Web Compiler
の略称で、Jestの実行速度をあげてくれるトランスパイラーを利用してみます。
$ yarn test
PASS src/App.test.tsx
✓ renders learn react link (30 ms)
SWC関連パッケージのインストールします。
$ yarn add -D @swc/core @swc/jest
SVG ファイル利用と、jest-dom関連のパッケージもインストールしておきます。
$ yarn add -D jest-svg-transformer @testing-library/jest-dom
Jestの設定ファイルを定義
$ yarn jest --init
? Would you like to use Jest when running "test" script in "package.json"?
no
? Would you like to use Typescript for the configuration file?
no
? Choose the test environment that will be used for testing
jsdom (browser-like)
? Do you want Jest to add coverage reports?
yes
? Which provider should be used to instrument code for coverage?
babel
? Automatically clear mock calls, instances and results before every test?
yes
jest.config.js
がプロジェクトディレクトリのルートに出力されます。
module.exports = {
clearMocks: true,
collectCoverage: true,
coverageDirectory: 'coverage',
moduleNameMapper: {
// Aliasの設定
'^@/(.+)': '<rootDir>/src/$1',
// Jest で svgファイルを扱えるようにする
'^.+\\.svg$': 'jest-svg-transformer'
},
roots: ['.'],
testEnvironment: 'jsdom',
testMatch: ['**/*.test.js', '**/*.test.ts', '**/*.test.tsx'],
testPathIgnorePatterns: ['/node_modules/'],
transform: {
'.+\\.(t|j)sx?$': [
'@swc/jest',
{
sourceMaps: true,
module: {
type: 'commonjs'
},
jsc: {
parser: {
syntax: 'typescript',
tsx: true
},
transform: {
react: {
runtime: 'automatic'
}
}
}
}
]
},
transformIgnorePatterns: ['/node_modules/']
}
Create React Appを rewired する
react-app-rewired
、customize-cra
パッケージを利用してちょっと上書きます。
$ yarn add -D react-app-rewired customize-cra
$ touch config-overrides.js
const {
override,
addWebpackResolve
} = require('customize-cra')
const path = require('path')
module.exports = override(
addWebpackResolve({
alias: {
'@': path.resolve(__dirname, './src/')
}
})
)
package.json
を修正してreact-app-rewired
で実行するように修正します。
{
...
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest test --coverage",
"lint:eslint": "eslint --fix src/**/*.{ts,tsx}"
},
...
}
ちょっとReactアプリ側を軽い感じにしておきます。
import logo from './logo.svg'
function App() {
return (
<div>
<img src={logo} className="App-logo" alt="logo" />
</div>
)
}
export default App
import { render } from '@testing-library/react'
import App from './App'
describe('App Component', () => {
test('renders main page correctly', async () => {
render(<App />)
})
})
jestを動かしてみます。
$ yarn test
PASS src/App.test.tsx
App Component
✓ renders main page correctly (46 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
App.tsx | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.252 s
Ran all test suites.
✨ Done in 5.62s.
小ネタ config-overrides.js
がeslintで怒られているので、.eslintignore
を作成して読み込まないようにしちゃいました。
touch .eslintignore
config-overrides.js
MUI v5をインストール
$ yarn add @mui/material @emotion/react @emotion/styled
MUIボタンのスタイルを適用してみる。
import logo from './logo.svg'
import Button from '@mui/material/Button' //テストで追記
function App() {
return (
<div>
<Button variant="contained">Hello World</Button>
<img src={logo} className="App-logo" alt="logo" />
</div>
)
}
export default App
MUIのスタイルがあたるのか確認します。
$ yarn start
ボタンにスタイルがあたっていれば完了です。
Emotionのスタイルを利用する
MUIではEmotionのスタイル適用ができるためその設定もしておく。
yarn add @emotion/css
yarn add -D @babel/preset-react @emotion/babel-plugin
const {
override,
addWebpackResolve,
addBabelPresets, // 追記
addBabelPlugins // 追記
} = require('customize-cra')
const path = require('path')
module.exports = override(
addBabelPresets(['@babel/preset-react']), //追記
addBabelPlugins(['@emotion/babel-plugin']), //追記
addWebpackResolve({
alias: {
'@': path.resolve(__dirname, './src/')
}
})
)
一旦ここまでで骨組みはできたと思います。
Discussion