์ค๋๋ถํฐ ์ฝ 3์ฃผ๊ฐ ์น ๋์์ด๋์ ํ์
์ผ๋ก ์์ ํ ์ด ํ๋ก์ ํธ๋ฅผ ์งํํ๊ฒ ๋์๋ค
ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ์์์ ๊ทธ ๋์ ์ฌ์ฉํด๋ณด๊ณ ์ถ๋ next.js์ redux-toolkit์ ์ฐ์ตํด๋ณด๋ ์ข์ ๊ธฐํ๊ฐ ๋ ๊ฒ ๊ฐ๋ค ๐
: Next.js, Typescript, redux-toolkit, emotion
ํ์
๋ฐ ํ๋ก์ ํธ ๊ด๋ฆฌ I Github
์ปค๋ฎค๋์ผ์ด์
I Jira
UI, ํ๋ฉด๊ตฌ์ฑ I Figma (๋์์ด๋์ ํ์
!)
ํ์ I ๊ฒ๋ํ์ด
Next.js๋?
: React๋ฅผ ๊ธฐ๋ฐ์ผ๋กํ๋ SSR(Server Side Rendering) ํ๋ ์์ํฌ
cf) React๋ CSR(Client Side Rendering)
npx create-next-app@latest --typescript
npm run dev
eslint์ prettier ์ค์ ์ ์ ๋ต์ด ์๋ค. ๊ทธ๋ฅ ์ฌ์ฉ์๊ฐ ํธํ๋๋ก ํธ์งํด์ ์ฌ์ฉํ๋ฉด๋๋ค.
ESLint
: Ecma Script Lint
Ecma์์ ๋ง๋ ํ์ค JS์ ๋ฐ๋ผ ๋ฌธ๋ฒ ์๋ฌ๋ฅผ ํ์ํด์ฃผ๋ ๋๊ตฌ๋ก ๋ณด๋ค ์ข์ ํ์ง์ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ํ ๊ฐ์ด๋
โจ ์๋ฌ์ ์ฝ๋ฉ ์คํ์ผ์ ์ก์์ฃผ๊ธฐ ๋๋ฌธ์ ํ์ ํ ๋ ์ ๋ฆฌ
Prettier
๋ชจ๋ ์ฝ๋๊ฐ ์ผ๊ด๋ ์คํ์ผ์ ์ค์ํ๋๋ก ๋ง๋ค์ด์ฃผ๋ ๋๊ตฌ
โจ ์ ์ฅ ์ ์ฝ๋ ํฌ๋ฉง
โจ ์๊ฐ,์๋์ง ์ ์ฝ ๊ฐ๋ฅ ์งฑํธํจ
์ค์นํ ๋ yarn์ด๋ npm ์ค ํธํ๊ฑธ๋ก ์ค์นํ๋ฉด ๋๋๋ฐ ํผ์ฉํ๋ฉด ์์ข๋ค๊ณ ํ๋ ํ๋๋ง ์กฐ์ง์
yarn add -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
์ด๊ฑธ ์ฌ์ฉํด๋ ๋๊ณ
npm install -D eslint-config-airbnb-typescript
์๋๋ฉด ์ฒ์๋ถํฐ ์ด๋ ๊ฒ ์ค์นํด๋ ๋จ
yarn add --save-dev typescript eslint-config-airbnb-typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser
npx install-peerdeps --dev eslint-config-airbnb
{
"env": {
"browser": true,
"node": true
},
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"airbnb",
"plugin:prettier/recommended",
"plugin:@typescript-eslint/recommended"
],
"settings": {
"react": {
"version": "detect"
},
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["react", "@typescript-eslint", "react-hooks", "prettier"],
"rules": {
"react/react-in-jsx-scope": 0,
"react/jsx-filename-extension": ["warn", { "extensions": [".tsx"] }],
"react/jsx-props-no-spreading": 0,
"react/function-component-definition": [
2,
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
]
},
"globals": {
"React": "writable"
}
}
์ผ๋จ defaul๋ก ๋ง๋ค์ด์ง ์น๊ตฌ๋คํํ ๋ฐ์ํ ์๋ฌ ์์ฃผ๋ก ๊บผ์คฌ๋ค. ์๋ง ํ๋ค๋ณด๋ฉด ๋ ์์ ํ๊ฒ ๋ ๊ฒ ๊ฐ์๋ฐ ๊ทธ๋๋ง๋ค ๊ธฐ๋ก ใฑใฑ
0์ด๋ฉด rule ์ ์ฉ ใดใด, 1์ด๋ฉด ์ ์ฉ ใ ใ
๐ Missing file extension "ts" import/extensions ์๋ฌ
airbnb rule๋ฅผ ํ์ฅํ๋ฉด ์ด๊ฑฐ ์์ด๋ ts ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค!"rules": { "import/extensions": [ "error", "ignorePackages", { "js": "never", "jsx": "never", "ts": "never", "tsx": "never" } ] }
๐ Next๋ React ์๋ import, ์จ์ฃผ์ง ์์๋ ๋จ
โจ "react/react-in-jsx-scope": 0,
๐ JSX not allowed in files with extension '.tsx'
โจ "react/jsx-filename-extension": ["warn", { "extensions": [".tsx"] }],
๐ props spreading is not allowed
โจ "react/jsx-props-no-spreading": 0
๐ ํจ์ํ ์ปดํฌ๋ํธ ๋ฐฉ์ ์ ์ธ, arrow function์ผ๋ก
โจ "react/function-component-definition": [ 2, { "namedComponents": "arrow-function", "unnamedComponents": "arrow-function" } ]
yarn add -D prettier eslint-config-prettier eslint-plugin-prettier
{
"singleQuote": true,
"semi": false,
"useTabs": false,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 80,
" arrowParens": "avoid",
"bracketSpacing": true
}
๐ค "singleQuote": true
๐โโ๏ธ ๋ฌธ์์ด ์์ ๋ฐ์ดํ cf) false: ํฐ ๋ฐ์ดํ
๐ค "semi": false
๐โโ๏ธ ์ธ๋ฏธ์ฝ๋ก ์ฌ์ฉ์ฌ๋ถ
๐ค "useTabs": false
๐โโ๏ธ ํญ ๋์ ์คํ์ด์ค
๐ค "tabWidth": 2
๐โโ๏ธ ๋ค์ฌ์ฐ๊ธฐ 2์นธ
๐ค ""trailingComma": "all"
๐โโ๏ธ ๊ฐ์ฒด๋ ๋ฐฐ์ด ๋ฑ์ ๋งจ ๋ง์ง๋ง์๋ ์ฝค๋ง
๐ค "printWidth": 80
๐โโ๏ธ ์ค ๋ฐ๊ฟ ํ ํญ ๊ธธ์ด
๐ค "arrowParens": "avoid"
๐โโ๏ธ ํ์ดํ ํจ์์์ ๋งค๊ฐ๋ณ์๋ฅผ ํ๋๋ง ๋ฐ์๋ ๊ดํธ ์๋ต
๐ค "bracketSpacing": true
๐โโ๏ธ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์์ ๊ดํธ์ ๊ณต๋ฐฑ ์ฝ์
์ฌ๋ถ
// prettier
"semi": true,
// eslint
"prettier/prettier": 0
์ด๋ ๊ฒ ์ค์ ์ ๋ง์ณค๋ค
๋ด์ผ๋ถํด ๋ณธ๊ฒฉ์ ์ผ๋ก next.js๋ฅผ ํ๋ด์ผ์ง ๐