2025. 8. 2. 14:49ใFront-end/Tools

๋ชฉ์ฐจ
1. ESLint๋?
2. โ๏ธ ESLint ์ค์น ๋ฐ ๊ธฐ๋ณธ ์ค์
3. ๐ Prettier ์ค์น ๋ฐ ESLint์ ์ฐ๋
4. ๐ ์ค์ ํ์ผ ์์ฑ (eslint.config.js)
5. ๐ค Husky + lint-staged๋ก ์ปค๋ฐ ์ ์๋ ๊ฒ์ฌ ์ค์
1. ESLint๋?
ESLint๋ JS/TS ์ฝ๋์์ ๋ฌธ๋ฒ ์ค๋ฅ, ์คํ์ผ ์๋ฐ, ๋ฒ๊ทธ ๊ฐ๋ฅ์ฑ ๋ฑ์ ์ฌ์ ์ ๊ฐ์งํ๋
์ ์ ๋ถ์ ๋๊ตฌ(linter)์ด๋ค.
ESLint๋ฅผ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๊ณผ์ ์ ์์๋ณด์.
- โ๏ธ ESLint ์ค์น ๋ฐ ๊ธฐ๋ณธ ์ค์ (+ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ)
- ๐ Prettier ์ค์น ๋ฐ ESLint์ ์ฐ๋
- ๐ ์ค์ ํ์ผ ์์ฑ (eslint.config.js)
- ๐ค Husky + lint-staged๋ก ์ปค๋ฐ ์ ์๋ ๊ฒ์ฌ ์ค์
2. โ๏ธ ESLint ์ค์น ๋ฐ ๊ธฐ๋ณธ ์ค์
๋ช ๋ น์ด๋ก eslint๋ฅผ ์ค์นํ์
npm install -D eslint
npx eslint --init
์ด ๋ ํ์ํ ํ๋ฌ๊ทธ์ธ๋ค์ ๊ฐ์ด ์ถ๊ฐํด๋ ๋๋ค.
npm install -D \
eslint \
@typescript-eslint/parser \
@typescript-eslint/eslint-plugin \
eslint-plugin-react \
eslint-plugin-react-hooks \
eslint-plugin-jsx-a11y \
eslint-plugin-prettier \
eslint-config-prettier \
eslint-plugin-storybook
- @typescript-eslint/parser : ESLint๊ฐ TypeScript ๋ฌธ๋ฒ์ ์ดํดํ ์ ์๊ฒ ํด์ฃผ๋ ํ์
- @typescript-eslint/eslint-plugin : TypeScript ์ ์ฉ ๋ฆฐํธ ๊ท์น์ ์ ๊ณตํ๋ ํ๋ฌ๊ทธ์ธ
- eslint-plugin-react : React ๋ฌธ๋ฒ ๋ฐ ์ปดํฌ๋ํธ ๊ด๋ จ ๋ฆฐํธ ๊ท์น ์ ๊ณต
- eslint-plugin-react-hooks : React Hooks ์ฌ์ฉ ๊ท์น์ ๊ฒ์ฌ (rules-of-hooks, exhaustive-deps ๋ฑ)
- eslint-plugin-jsx-a11y : JSX ์ฝ๋์์ ์ ๊ทผ์ฑ(a11y) ๊ด๋ จ ๋ฌธ์ ๋ฅผ ๊ฐ์ง
- eslint-plugin-prettier : Prettier ํฌ๋งทํ ์ค๋ฅ๋ฅผ ESLint๋ก ํ์
- eslint-config-prettier : Prettier์ ์ถฉ๋ํ๋ ESLint ๊ท์น์ ๋นํ์ฑํ
- eslint-plugin-storybook : Storybook ์ฝ๋์ ๋ง๋ ๋ฆฐํธ ๊ท์น ์ ๊ณต (๊ตฌ์ฑ ์์, ๋ฉํ ์ ์ ๋ฑ)
์๋๋ผ๋ฉด Prettier๋ ๊ฐ์ด ์ค์น/์ค์ ํด์ผํ๋ค. ๊ทผ๋ฐ ๋ฐ๋ก ์ ๋ฆฌํด์ ๋ด์ฉ์ด ๋๋ ์ง
>> Prettier ๊ด๋ จ ๊ธ
3. ๐ Prettier์ ESLint ์ฐ๋
์ฝ๋ ์คํ์ผ ์๋ ํฌ๋งทํฐ์ธ prettier์ ESLint๋ ์ถฉ๋ํ ๊ฐ๋ฅ์ฑ๋ ์๋ค.
๋์ด ์ถฉ๋ํ์ง ์๋๋ก ํ๊ธฐ ์ํด eslint-config-prettier๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ค.
์ถฉ๋ ๋ฐฉ์ง๋ฅผ ์ํด ์๋์ ์์ฑํ .eslintrcํ์ผ์ ์๋ ์ค์ ์ ์ถ๊ฐํ๋ค.
"extends": ["plugin: "pretier/recomended"]
์ด ์ค์ ์ผ๋ก ESLint๋ Prettier์ ์ถฉ๋ํ๋ ์ฝ๋ ์คํ์ผ ๊ท์น์ ๋๋ค.
4. ๐ ์ค์ ํ์ผ ์์ฑ (.eslintrc, .eslintignore)
eslint ๊ท์น์ ์์ฑํ๋ .eslint.config.js๋ฅผ ์์ฑํ์.
์ฒ์์๋ .eslintrc๋ก ์์ฑ์ ํ์์ผ๋, ์ ์ง๋ณด์์ ์ฉ์ด์ ์ฑ๋ฅ ํฅ์ ๋ชฉ์ ์ผ๋ก ESLint v9 ๋ถํฐ๋ Flat Config ๋ฐฉ์์ด ๋์
๋์ด
eslint.config.js๊ฐ ๊ธฐ๋ณธ ์ค์ ๋ฐฉ์์ผ๋ก ๋ฐ๋์๋ค๊ณ ํ๋ค. >>
eslint์ ๊ฒ์ฌ์์ ๋ฌด์ํ ํ์ผ๋ค์ ์์ฑํ๋ .eslintignore์ ์์ฑํ์.
.eslint.config.js (ESLint Flat Config ํ์)
import { FlatCompat } from "@eslint/eslintrc";
import tsPlugin from "@typescript-eslint/eslint-plugin";
import reactPlugin from "eslint-plugin-react";
import reactHooksPlugin from "eslint-plugin-react-hooks";
import prettierPlugin from "eslint-plugin-prettier";
import jsxA11yPlugin from "eslint-plugin-jsx-a11y";
import storybookPlugin from "eslint-plugin-storybook";
import { dirname } from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const config = [
...compat.extends("next/core-web-vitals", "next/typescript"),
{
plugins: {
"@typescript-eslint": tsPlugin,
react: reactPlugin,
"react-hooks": reactHooksPlugin,
prettier: prettierPlugin,
"jsx-a11y": jsxA11yPlugin,
storybook: storybookPlugin,
},
languageOptions: {
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
},
},
rules: {
"react/react-in-jsx-scope": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
vars: "all",
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
},
],
"require-jsdoc": "off",
"react/display-name": "off",
"react-hooks/exhaustive-deps": "warn",
"prettier/prettier": "error",
"jsx-a11y/anchor-is-valid": [
"error",
{
components: ["Link"],
specialLink: ["hrefLeft", "hrefRight"],
aspects: ["invalidHref", "preferButton"],
},
],
},
},
];
export default config;
๊ฐ ํญ๋ชฉ๋ค ๊ฐ๋จํ ์ค๋ช
| import { FlatCompat } ... | FlatCompat์ ๊ธฐ์กด .eslintrc ๊ธฐ๋ฐ ์ค์ ์ ESLint Flat Config ๋ฐฉ์์ผ๋ก ๋ณํํด์ฃผ๋ ๋์ฐ๋ฏธ๋ค. Next.js ๋ฑ์ ์ค์ ๋ค์ด ์์ง FlatConfig๋ฅผ ์ง์ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์ ํ์ํ๋ค. >> |
| import ...(Plugin) | FlatConfig ๋ฐฉ์์์๋ ํ๋ฌ๊ทธ์ธ์ ์ง์ importํด์ ๋ฑ๋กํด์ผํ๋ค. |
| import dirname import fileURLToPath |
FlatCompat์ ํ์ฌ ํ์ผ ์์น๋ฅผ ์ ๋ฌํ๊ธฐ ์ํด ํ์ฌ ํ์ผ ๊ฒฝ๋ก๋ฅผ ๊ตฌํ๋ ์ฝ๋์ด๋ค. ESM ํ๊ฒฝ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ๋ฐฉ์์ ์ฌ์ฉํ๋ค. |
| const compat | .eslintrc์์ ์ฌ์ฉํ๋ extends: "next/core-web-vitals"๊ฐ์ ์ค์ ์ FlatConfig์์๋ ์ฌ์ฉ ๊ฐ๋ฅํ๋๋ก ๋ณํํด์ค๋ค. |
| const config = [ ...compat.extends(...), |
Next.js ํ๋ก์ ํธ์์ ์ถ์ฒํ๋ ๊ธฐ๋ณธ ESLint ์ค์ ์ ๋ถ๋ฌ์ config ๋ฐฐ์ด์ ํฌํจ์ํจ๋ค. |
| plugins: { ... } | importํ ํ๋ฌ๊ทธ์ธ๋ค์ ESLint์ ๋ช ์์ ์ผ๋ก ๋ฑ๋กํ๋ค. |
| languageOptions: { ... } | ์ต์ JS ๋ฌธ๋ฒ, ๋ชจ๋ ์์คํ ์ ์ฌ์ฉํ๋ค๊ณ ํ์ ์ค์ ์ ํ๋ค. |
| rules : { ... } | ⋅ react-injsx-scope : React17๋ถํฐ JSX๋ฅผ ์ฌ์ฉํ ๋ react๋ฅผ importํ์ง ์์๋ ๋ผ์ off ⋅ no-unused-vars : ์ฌ์ฉ๋์ง ์๋ ๋ณ์/๋งค๊ฐ๋ณ์๋ฅผ ์๋ฌ์ฒ๋ฆฌ(์ด๋ฆ์ด _๋ก ์์ํ๋ฉด ๋ฌด์) ⋅ require-jsdoc : JSDoc ์ฃผ์ ํ์ ๊ท์น off ⋅ display-name : ์ต๋ช ํจ์ ์ปดํฌ๋ํธ์ displayName ์๋ค๊ณ ๊ฒฝ๊ณ x ⋅exhaustive-deps : useEffect ๋ฑ์์ ์์กด์ฑ ๋ฐฐ์ด ๋๋ฝ ์ ๊ฒฝ๊ณ ⋅prettier/prettier : Prettier ํฌ๋งทํ ์ค๋ฅ ์, ESLint ์๋ฌ๋ก ์ฒ๋ฆฌ anchor-is-valid : Link ์ปดํฌ๋ํธ ์ ํจ์ฑ ๊ฒ์ฌ (๋น href, ์๋ชป๋ ๋งํฌ ๋ฑ ๊ฒ์ฌ) |
| export default config; | ์์์ ์์ฑํ ESLint ์ค์ ์ export ⋅ Flat Config์์๋ ์ค์ ํ์ผ์ด ๋ฐ๋์ config ๊ฐ์ฒด ๋ฐฐ์ด์ export default ํด์ผ ํ๋ค.(๋ฐฐ์ดํ ์ค์ ๋ฐฉ์) ⋅ ๊ฐ์ฒด ๋จ์๋ก ์ค์ ์ด ๋ณํฉ๋๋ฉฐ, ๋์ค ์์์ ๋ฑ์ฅํ ์ค์ ์ด ์ฐ์ ์ ์ฉ๋๋ค. ⋅ ๋ฐฐ์ด ํํ ์์ด export default config [...]์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์์ฑํ๋ฉด Flat Config ๋ฌธ๋ฒ ์๊ตฌ์ฌํญ ๋ฏธ๋ฌ๋ก ESLint๊ฐ ์ธ์ํ์ง ๋ชปํ ์ ์์ผ๋ฏ๋ก, ๋ฐฉ์์ ๋ง์ถ์. |
.eslintignore
ESLint ์ต์ ๋ฒ์ (9.x ์ด์) ๋ถํฐ๋ .eslintignore ๋์ eslint.config.js๋ด์ ignores ์ต์ ์ ์ฌ์ฉํ๋ ๋ฐฉ์์ ๊ถ์ฅํด์
.eslintignore๋ฅผ ์์ฑํ๋ ๊ฒ ์๋๋ค.
5. ๐ค Husky + lint-staged๋ก ์ปค๋ฐ ์ ์๋ ๊ฒ์ฌ ์ค์
์ ์์ฑํ ์ค์ ๋ค์ ์๋์ผ๋ก ํจ์จ์ ์ผ๋ก ์ ์ฉํ๊ธฐ ์ํด Husky์ lint-staged๊ฐ ํ์ํ๋ค.
- husky : ์๋ํ
- lint-staged : ํจ์จ (staging ํ์ผ๋ง ๊ฒ์ฌํ๋ค.)
Husky
๋ถ๋ช ๊ธ์ ์ผ๋ ๊ธฐ์ต์ด ์๋๋ฐ.. ์ด๊ฑด ์๋ฌดํผ ๋ฐ๋ก ์ ๋ฆฌํ ๊ฑฐ๋ค.
lint-staged
1. husky pre-commit ํ ์ค์
husky์ pre-commit ํ ์์ npx lint-staged๋ฅผ ์คํํ๋๋ก ๋ช ๋ น์ด๋ฅผ ์์ฑํ๋ค.
npx husky add .husky/pre-commit "npx lint-staged"
์ด๋ฌ๋ฉด pre-commit ํ์ผ์ ๋ด์ฉ์ด ์์ฑ๋๋๋ฐ, ์ฌ๊ธฐ์ lint ๊ฒ์ฌ ์๋ฌ ๋ฐ์์ ํ์คํ๊ฒ ์ปค๋ฐ ์ค์งํ๊ณ ์ถ๋ค!!
ํ๋ฉด exit 1์ ๋ช ์ํด์ ํ์คํ๊ฒ ์ค์ง์ํค๋๋ก ์์ ํ์.
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged || exit 1
2. package.json ์ค์
package.json์ lint-staged์ ๋ํ ๋ช ๋ น์ด ๋จ์ถ์ด๋ฅผ ์์ฑํ์.
"lint-staged": {
"*.{ts,tsx,js}": [
"eslint --fix --max-warnings=0",
"prettier --write",
"eslint --fix"
],
"*.{json,md,css,html}": [
"prettier --write"
]
},
- .ts, .tsx, .js ํ์ฅ์๋ฅผ ๊ฐ์ง ํ์ผ์ ๋์์ผ๋ก ํ๋ค.
1. ESLint ์๋ ์์ + ๊ฒฝ๊ณ ํ๊ฐ๋ผ๋ ์์ผ๋ฉด ์ปค๋ฐ ์คํจ(max-warnings=0)
→ ํ ๊ท๋ชจ๊ฐ ํฌ๊ฑฐ๋ ๋ ๊ฑฐ์ ์ฝ๋๊ฐ ๋ง์ ๊ฒฝ์ฐ, ๊ฒฝ๊ณ ๋ฅผ ํ์ฉํ๊ณ ์ ์ง์ ๊ฐ์ ์ ํ๋ ๊ฒ์ด ํ์ค์ ์ด๋ค.(max-warnings=10)
2. Prettier๋ก ์ฝ๋ ์คํ์ผ ํฌ๋งท ์ ์ฉ
3. ESLint ์๋ ์์ ์ ํ ๋ฒ ๋ ์ํํ์ฌ ํฌ๋งทํ ์ดํ ๋ฐ์ํ ์ ์๋ ์ด์๋ฅผ ์ก์ - .json, .md, .css, .html ํ์ฅ์๋ฅผ ๊ฐ์ง ํ์ผ์ ๋์์ผ๋ก ํ๋ค.
→ ๋ฆฐํธ ๊ฒ์ฌ๋ฅผ ํ์ง ์๊ณ Prettier ์ฝ๋ ์คํ์ผ ํฌ๋งท๋ง ์ ์ฉ
์์ ๊ฐ์ด eslint --fix๋ฅผ ๋ ๋ฒ ์ ์ฉํ๋ฉด ๋ ํ์ง์ด ๋์ ๊ฒ์ฌ๋ฅผ ํ ์ ์์ผ๋, ์๋ ๋ฐ ํจ์จ์ด ์กฐ๊ธ ๋จ์ด์ง๋ค.
๊ฐ๊ฒฐํ๊ฒ ์๋์ ๊ฐ์ด ๋ฆฐํธ๋ฅผ ์ํํด๋ ์ ์ค๊ณ๋ ์ค์ ์์๋ ๋๋ถ๋ถ์ ํฌ๋งทํ /์ถฉ๋ ๋ฌธ์ ๋ ๋ฐ์ํ์ง ์๋๋ค.
"*.{ts,tsx,js}": [
"prettier --write",
"eslint --fix --max-warnings=0"
]
์ฐธ๊ณ
https://eslint.org/docs/latest/
Documentation - ESLint - Pluggable JavaScript Linter
A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease.
eslint.org
https://github.com/lint-staged/lint-staged
GitHub - lint-staged/lint-staged: ๐ซ๐ฉ — Run tasks like formatters and linters against staged git files
๐ซ๐ฉ — Run tasks like formatters and linters against staged git files - lint-staged/lint-staged
github.com
https://cwdeveloper.tistory.com/67
husky + lint-staged๊ฐ ํ์ํ ์ด์ (prettier + eslint)
์ค๋์ ๋ฌธ์ - github Merge ์ค์ ๋ฐ์ํ ๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ์ฌํญ์ ์ ๋ฐ์ดํธํ๊ณ merge๋ฅผ ํ๋๋ฐ Vecel์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค๊ณ ๊ฒฝ๊ณ ์ฐฝ์ด ๋ด๋ค. group/management/managementClient.tsx ํ์ผ์์ Table์ ๋ํ iss
cwdeveloper.tistory.com
https://velog.io/@jaychang99/Husky-lint-staged-%EC%A0%95%EB%B3%B5%ED%95%98%EA%B8%B0
Husky, lint-staged ์ ๋ณตํ๊ธฐ.
๊ฐ๋ ฅํ ํ์ ๋ฐ git hook ํด, husky, lint-staged ์ ๋ํด ์์๋ณด์!
velog.io
'Front-end > Tools' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ESLint : FlatCompat๊ณผ FlatConfig (4) | 2025.08.08 |
|---|---|
| Prettier ์ธํ ํ๊ธฐ (5) | 2025.08.02 |
| Google fonts ์ฌ์ฉํด๋ณด๊ธฐ (1) | 2025.07.24 |
| Netlify์ผ๋ก ํธ์คํ ์ ํด๋ณด์ (3) | 2025.07.24 |
| Webpack์ ๋ญ๊น (4) | 2025.07.09 |
GitHub