๐Ÿ‘”

(ํ”„๋กฑ์ด)ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ ์„ค์ •

์š”์•ฝ

  1. create-react-app, Typescript
  1. ESlint, Prettier
  1. emotion/styled
  1. storybook
  1. axios

1) create-react-app & Typescript

  • ๊ธฐ๋ณธ: yarn ๊ธฐ๋ฐ˜ ํŒจํ‚ค์ง€
  • CRA๋ฅผ Typescript ๋ฒ„์ „์œผ๋กœ ์„ค์น˜.
yarn create react-app yas --template typescript
 

tsconfig.json

{ "compilerOptions": { "target": "es6", // ๊ธฐ๋ณธ๊ฐ’: es5 => es6๋กœ ์ˆ˜์ • "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": [ "src" ], }

2) ESLint & Prettier ์„ค์ •

yarn add -D eslint prettier yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser // ESLint Rule ์ถ”๊ฐ€ ํ”Œ๋Ÿฌ๊ทธ์ธ yarn add -D eslint-config-airbnb // airbnb ESLint ๊ทœ์น™ yarn add -D eslint-config-prettier eslint-plugin-prettier // prettier Rule ํ”Œ๋Ÿฌ๊ทธ์ธ yarn add -D eslint-plugin-react eslint-plugin-react-hooks // airbnb ESLint ๊ทœ์น™ yarn add -D eslint-plugin-jsx-a11y eslint-plugin-import // airbnb ESLint ๊ทœ์น™

package.json

  • ์„ค์น˜ ์™„๋ฃŒ ํ›„ ์•„๋ž˜์˜ devDependencies๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.
// ... "devDependencies": { "@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/parser": "^5.4.0", "eslint": "^8.3.0", "eslint-config-airbnb": "^19.0.1", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.3", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-react": "^7.27.1", "eslint-plugin-react-hooks": "^4.3.0", "prettier": "^2.5.0" } // ...

.eslintrc.js

  • ์ž๋™ ์ƒ์„ฑ๋œ .eslintrc.js ์ฝ”๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์—ฌ rule์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
module.exports = { env: { browser: true, node: true, // node: true, commonjs: true ์ถ”๊ฐ€ commonjs: true, // ์‚ฌ์ „ ์ •์˜๋œ static ๋ฉ”์„œ๋“œ๋ฅผ ์ธ์‹ํ•  ์ˆ˜ ์—†์–ด์„œ ์—๋Ÿฌ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ESLint ๊ฒฝ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ์ถ”๊ฐ€ es2021: true, }, extends: [ 'airbnb', 'plugin:react/recommended', 'plugin:jsx-a11y/recommended', 'plugin:import/errors', 'plugin:import/warnings', 'plugin:@typescript-eslint/recommended', ], parser: '@typescript-eslint/parser', parserOptions: { ecmaFeatures: { jsx: true, }, ecmaVersion: 2018, sourceType: 'module', }, plugins: ['react', '@typescript-eslint'], rules: { 'linebreak-style': 0, 'import/prefer-default-export': 0, 'import/extensions': 0, 'no-use-before-define': 0, 'import/no-unresolved': 0, 'react/react-in-jsx-scope': 0, 'import/no-extraneous-dependencies': 0, 'no-shadow': 0, 'react/prop-types': 0, 'react/jsx-one-expression-per-line': 0, 'func-names': ['error', 'as-needed'], 'react/jsx-filename-extension': [ 2, { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, ], 'object-curly-newline': [ 'error', { ExportDeclaration: { multiline: true, minProperties: 2, }, }, ], 'jsx-a11y/no-noninteractive-element-interactions': 0, '@typescript-eslint/explicit-module-boundary-types': 0, }, settings: { 'import/resolver': { node: { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, }, }, };

.prettierrc

  • ๋ฃจํŠธ ํด๋”์— .prettierrc ํŒŒ์ผ ์ƒ์„ฑ ํ›„ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.
{ "singleQuote": true, "semi": true, "useTabs": false, "tabWidth": 2, "trailingComma": "all", "printWidth": 80, "arrowParens": "always", "orderedImports": true, "bracketSpacing": true, "jsxBracketSameLine": false }

3) emotion, styled

  • styled component
  • javascript ํŒŒ์ผ ๋‚ด๋ถ€์—์„œ ์Šคํƒ€์ผ ์ ์šฉ ํŒจํ‚ค์ง€
yarn add @emotion/react // emotion yarn add --dev @emotion/babel-plugin // babel yarn add @emotion/styled // styled
 
// ... "dependencies": { "@emotion/react": "^11.6.0", "@emotion/styled": "^11.6.0", // ...
 

craco(create-react-app-config-override)

  • ์œ„์˜ ํŒจํ‚ค์ง€ 3๊ฐœ๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด styled ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋งˆ๋‹ค /** @jsxImportSource @emotion/react */ fragma ์ฃผ์„์„ ์ถ”๊ฐ€ํ•ด์•ผ ๋˜๋Š”๋ฐ, ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด craco๋ฅผ ์„ค์น˜ํ•œ๋‹ค.
yarn add -D @craco/craco yarn add -D @emotion/babel-preset-css-prop
 

craco.config.js

  • ๋ฃจํŠธ ํด๋”์— craco.config.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด ์ถ”๊ฐ€ํ•œ๋‹ค.
module.exports = { babel: { presets: ["@emotion/babel-preset-css-prop"] } }
 

package.json

  • package.json ํŒŒ์ผ์—์„œ scripts ๋ถ€๋ถ„์„ react-scripts์—์„œ craco๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
// ... "scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "craco eject" }, // ...
 
 

4) Storybook

  • UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ชจ์•„ ๋ฌธ์„œํ™”ํ•˜๊ณ  ๋ณด์—ฌ์ฃผ๋Š” ์˜คํ”ˆ์†Œ์Šค Tool
npx -p @storybook/cli sb init
notion image
 

storybook ์„ค์น˜ ํ›„ start ์˜ค๋ฅ˜

  • storybook ์„ค์น˜ ํ›„ react-scripts์™€ storybook์˜ babel-loader ๋ฒ„์ „์ด ๋‹ฌ๋ผ์„œ yarn start๋กœ ๋กœ์ปฌ ํ™˜๊ฒฝ Open์ด ๋˜์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ๋‹ค.
  • package.json ํŒŒ์ผ์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.
// package.json // ... "resolutions": { "babel-loader": "8.1.0" } // ...
 
 
 

5) Axios

  • ๋ธŒ๋ผ์šฐ์ €, Node.js๋ฅผ ์œ„ํ•œ Promise API๋ฅผ ํ™œ์šฉํ•˜๋Š” HTTP ๋น„๋™๊ธฐ ํ†ต์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
yarn add axios
 

6) .env

  • ESLint ์„ค์น˜ ํ›„ package.json๊ณผ yarn.lock์—์„œ์˜ package version ์ฐจ์ด๊ฐ€ ๋ฐœ์ƒํ•ด์„œ yarn start ๊ฐ™์€ ๋กœ์ปฌ ํ™˜๊ฒฝ์ด Open๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋ฃจํŠธ ํด๋”์— .env ํŒŒ์ผ์„ ์ƒ์„ฑ ํ›„ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
SKIP_PREFLIGHT_CHECK=true

์ตœ์ข… package.json

{ "name": "yas", "version": "0.1.0", "private": true, "dependencies": { "@emotion/react": "^11.6.0", "@emotion/styled": "^11.6.0", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "@types/jest": "^26.0.15", "@types/node": "^12.0.0", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", "axios": "^0.24.0", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3", "typescript": "^4.1.2", "web-vitals": "^1.0.1" }, "scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "craco eject", "storybook": "start-storybook -p 6006 -s public", "build-storybook": "build-storybook -s public" }, "resolutions": { "babel-loader": "8.1.0" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ], "overrides": [ { "files": [ "**/*.stories.*" ], "rules": { "import/no-anonymous-default-export": "off" } } ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "@craco/craco": "^6.4.2", "@emotion/babel-plugin": "^11.3.0", "@emotion/babel-preset-css-prop": "^11.2.0", "@storybook/addon-actions": "^6.3.12", "@storybook/addon-essentials": "^6.3.12", "@storybook/addon-links": "^6.3.12", "@storybook/node-logger": "^6.3.12", "@storybook/preset-create-react-app": "^3.2.0", "@storybook/react": "^6.3.12", "@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/parser": "^5.4.0", "eslint": "8.3.0", "eslint-config-airbnb": "^19.0.1", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.3", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-react": "^7.27.1", "eslint-plugin-react-hooks": "^4.3.0", "prettier": "^2.5.0" } }