realworld와 다음과 같은 기술 스텍을 이용해 react app을 만들고, 해당 서비스를 배포해가는 과정을 기록하기 위한 글이다.
- yarn2
- TypeScript v4.3.x
- react-scripts v4.x.x
- React v17.x.x
- React Router v 6.x
- emotion v11.4.x
- Storybook v6.3.x
- @testing-library/react v12.x.x
Create React App
create-react-app을 이용해서 기본적인 react app을 생성한다.
TypeScript를 사용하기 위해 --template typescript
옵션을 추가해주었다.
npx create-react-app my-app --template typescript
Configure yarn2
yarn2를 패키지 매니저로 사용하기 위해 해당 프로젝트에 설정을 해주었다.
- 설정 과정 참고 : https://github.com/gloriaJun/til/issues/125
Configure ESLint, Prettier
eslint와 prettier 설정을 위해 아래와 같은 패키지를 설치한다.
- npm
- Yarn
- pnpm
npm install -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-plugin-prettier prettier
yarn add --dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-plugin-prettier prettier
pnpm add -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-plugin-prettier prettier
아래의 패키지들은 각자 프로젝트에 정의하는 규칙에 따라 달라질 수 있다.
- npm
- Yarn
- pnpm
npm install -D eslint-config-react eslint-import-resolver-babel-module eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks
yarn add --dev eslint-config-react eslint-import-resolver-babel-module eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks
pnpm add -D eslint-config-react eslint-import-resolver-babel-module eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks
- .eslint.rc : https://gist.github.com/gloriaJun/fd5dd389cf727faba1ad66a3cb7427ee#file-eslint-rc
- .prettierrc : https://gist.github.com/gloriaJun/fd5dd389cf727faba1ad66a3cb7427ee#file-prettierrc
package.json에 lint를 실행하기 위한 스크립트를 다음과 같이 추가한다.
// package.json
"prelint": "tsc --noEmit",
"lint": "eslint --ext=jsx,ts,tsx src",
Configure lint-staged, husky
git stage에 올라간 파일에 대해 git hook을 이용해 lint를 수행하기 위해 lint-staged와 husky를 설치한다
- 패키지를 설치한다.
- npm
- Yarn
- pnpm
npm install husky lint-staged --dev
yarn add husky lint-staged --dev
pnpm add husky lint-staged --dev
.lintstagedrc.js
파일을 생성하고 https://gist.github.com/gloriaJun/fd5dd389cf727faba1ad66a3cb7427ee#file-lintstagedrc-js 와 같이 정의한다.- husky hook을 생성한다.
npx husky install
- commit 이전에 lint를 수행하기 위해
.husky/pre-commit
파일을 다음과 같이 정의한다.
npx husky add .husky/pre-commit "yarn lint-staged"
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint-staged
Configure commitlint
commitlint는 git hook을 이용하여 commit 메시지에 대한 커밋 메시지 스타일 체크를 위한 패키지이다.
- 패키지를 설치한다.
- npm
- Yarn
- pnpm
npm install -D @commitlint/cli @commitlint/config-conventional
yarn add --dev @commitlint/cli @commitlint/config-conventional
pnpm add -D @commitlint/cli @commitlint/config-conventional
.commitlintrc.js
파일을 생성하고 https://gist.github.com/gloriaJun/fd5dd389cf727faba1ad66a3cb7427ee#file-commitlintrc-js와 같이 정의한다..husky/commit-msg
파일을 생성하고 아래와 같이 정의한다.
npx commitlint --edit $1
Configure storybook
- storybook을 설치한다.
npx sb init
- package.json의 아래와 같이
eslintConfig
항목에 정의된 부분을.eslintrc.js
설정 파일로 옮겨서 정의해준다.
"eslintConfig": {
"overrides": [
{
"files": [
"**/*.stories.*"
],
"rules": {
"import/no-anonymous-default-export": "off"
}
}
]
},
스토리북이 정상적으로 설치가 완료되고, 아래와 같이 실행하여 스토리북 서비스가 기동이 잘 되는 지 확인해볼 수 있다.
- npm
- Yarn
- pnpm
# Starts Storybook in development mode
npm run storybook
# Starts Storybook in development mode
yarn storybook
# Starts Storybook in development mode
pnpm run storybook
해당 과정까지 문제없이 수행이 되었다면, react-app 생성은 완료된 것이다.
Trouble Shooting
husky - Hooks not running
아래와 같은 메시지를 보여주며 husky가 동작을 하지 않는다면....
정의한 hook 파일의 파일 권한에 chmod +x .husky/<hookname>
을 수행하여 실행 권한을 추가해주어야 한다.
╰─❯ git ci -m "chore: add husky"
힌트: '.husky/pre-commit' 후크가 실행 가능하도록 설정되지 않아서, 무시됩니다.
힌트: 이 경고는 `git config advice.ignoredHook false` 명령으로 끌 수 있습니다.
[master af6b6e3] chore: add husky
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 .husky/pre-commit
ERROR in ./.yarn/$$virtual/@pmmmwh-react-refresh-webpack-plugin-virtual...
스토리북 실행 중에 아래와 같은 오류가 발생하면..
ERROR in Failed to load config "react-app" to extend from.
Referenced from: /Users/user/Documents/mio/my-app/package.json
ERROR in ./.yarn/$$virtual/@pmmmwh-react-refresh-webpack-plugin-virtual-5ef0209fe8/0/cache/@pmmmwh-react-refresh-webpack-plugin-npm-0.4.3-5375cf6b6f-718853bf7b.zip/node_modules/@pmmmwh/react-refresh-webpack-plugin/sockets/WHMEventSource.js
Module not found: Error: @pmmmwh/react-refresh-webpack-plugin tried to access webpack-hot-middleware (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound.
Required package: webpack-hot-middleware (via "webpack-hot-middleware/client")
Required by: @pmmmwh/react-refresh-webpack-plugin@virtual:aa8e2a7880c7d78a363a64638c8d08e1ed334a2ec81820e6145b829d0a51f0466091afc671f5cadd8190c27d433059941023876a9c0e48dc23dca7c6014ea052#npm:0.4.3 (via /Users/user/Documents/mio/my-app/.yarn/$$virtual/@pmmmwh-react-refresh-webpack-plugin-virtual-5ef0209fe8/0/cache/@pmmmwh-react-refresh-webpack-plugin-npm-0.4.3-5375cf6b6f-718853bf7b.zip/node_modules/@pmmmwh/react-refresh-webpack-plugin/sockets/WHMEventSource.js)
Ancestor breaking the chain: @storybook/preset-create-react-app@virtual:ddccc941eb8b35cd4b898a64351d8bba4ecc85eb47e8f1b36dce7852d6c3635665e0fc5464861f723d175edb2248ce0fa54dfefb9b5e4d2fdaef4b2353c4aa82#npm:3.1.7
다음과 같은 패키지를 설치 후, 다시 기동하여 확인한다.
- npm
- Yarn
- pnpm
npm install -D webpack-hot-middleware
yarn add --dev webpack-hot-middleware
pnpm add -D webpack-hot-middleware
lint Error
위와 같이 실행 후, yarn lint
를 수행하면 아래 예시와 같이 에러가 발생한다.
/Users/user/Documents/mio/my-app/src/App.test.tsx
2:1 error There should be at least one empty line between import groups import/order
8:3 error Unsafe call of an `any` typed value @typescript-eslint/no-unsafe-call
/Users/user/Documents/mio/my-app/src/App.tsx
1:1 error There should be at least one empty line between import groups import/order
/Users/user/Documents/mio/my-app/src/index.tsx
2:1 error There should be at least one empty line between import groups import/order
7:1 error Caution: `ReactDOM` also has a named export `render`. Check if you meant to write `import {render} from 'react-dom'` instead import/no-named-as-default-member
11:34 error Insert `,` prettier/prettier
// ...SKIP
이 부분은 커스텀하여 정의된 lint 규칙과 스토리북과 cra에서 생성하여 정의한 코딩 스타일이 맞지 않아서 발생하는 부분이다.
그리고 아래의 구문에서 발생하는 에러는..
// App.test.tsx
expect(linkElement).toBeInTheDocument();
// Property 'toBeInTheDocument' does not exist on type 'JestMatchers<HTMLElement>'.ts(2339)
// 9:3 error Unsafe call of an `any` typed value @typescript-eslint/no-unsafe-call
yarn add -D @types/testing-library__jest-dom
를 실행 후에 tsconfig.json에 다음과 같이 추가해주어 해결할 수 있다.
// tsconfig.json
"types": [
"@types/jest",
"@types/testing-library__jest-dom",
]