Prettier์™€ ESLint๋ž€ ๐Ÿค”

๊น€์ •๋ฏผยท2022๋…„ 5์›” 25์ผ
0

1. Prettier๋ž€

1. Prettier๋ž€

ํŒŒ์ผ์„ ์ €์žฅํ• ๋•Œ๋งˆ๋‹ค, ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ํ˜•์‹์œผ๋กœ ๋ชจ์–‘์„ ์˜ˆ์˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” Node.js ํŒจํ‚ค์ง€์ด๋‹ค

ํŒŒ์ผ์„ ์ €์žฅํ• ๋•Œ๋งˆ๋‹ค ์ผ๊ด€์„ฑ์žˆ๊ฒŒ ์ฝ”๋“œ๋ฅผ ์งค ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

// prettier-ignore (Before)
foo(gatsbyLongArg(),soManyParameters(),gatsbyInit(),gatsbyMustUsedIt(), gatsbyPrettierConfigThis())
//(after)
foo(
  gatsbyLongArg(),
  soManyParameters(),
  gatsbyInit(),
  gatsbyMustUsedIt(),
  gatsbyPrettierConfigThis()
)

Prettier๋Š” VSCode ํ™•์žฅ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜์—ฌ ์„ค์น˜ํ•ด ์ค„ ์ˆ˜์žˆ๊ณ  Node์˜ npm ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์„ค์น˜๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค

2. ์‚ฌ์šฉ๋ฒ•

(1) ์„ค์น˜

npm i -D prettier

(2) ์„ค์ •

Prettier ์„ค์ •ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ ( .prettierrc.json )

์ด์ œ ๋Œ€ํ‘œ์ ์ธ ์„ค์ •์„ ์•Œ์•„๋ณผํ…๋ฐ, ๊ทธ ์™ธ ์„ค์ •์€ ์—ฌ๊ธฐ์„œํ™•์ธ : prettier.io/docs/en/options.html

singleQuote: ๋ฌธ์ž์—ด ์ž…๋ ฅ์‹œ " ๋ฅผ ์“ธ์ง€ ' ๋ฅผ ์‚ฌ์šฉํ• ์ง€ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ €๋Š” ' ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์— true๋กœ ์„ค์ •ํ•ด ๋†“์•˜์Šต๋‹ˆ๋‹ค.

semi: ์„ธ๋ฏธ์ฝœ๋ก (;) ์‚ฌ์šฉ์— ๊ด€ํ•œ ์„ค์ •์ด์—์š”. ์ €๋Š” ์‚ฌ์šฉํ•˜๋ฏ€๋กœ true ๋กœ ๋†“๊ณ  ์‚ฌ์šฉํ•ด์š”.

tabWidth: ๋“ค์—ฌ์“ฐ๊ธฐ์˜ ํฌ๊ธฐ๋ฅผ ์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ €๋Š” 2์นธ์œผ๋กœ ๋†“๊ณ  ์จ์š”. 4์นธ์œผ๋กœ ๋†“๊ณ  ์“ฐ๋ฉด ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์ค‘์ฒฉ๋  ์‹œ์— ์ฝ”๋“œ ๋’ท๋ถ€๋ถ„์ด ์•ˆ๋ณด์ด๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธฐ๋”๋ผ๊ตฌ์š”....ใ…œ

trailingComma: ๊ฐ์ฒด ๋˜๋Š” ๋ฐฐ์—ด์ด ์—ฌ๋Ÿฌ์ค„๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งจ ๋งˆ์ง€๋ง‰ ์ค„์— ์‰ผํ‘œ๋ฅผ ๋ถ™์—ฌ์ค„์ง€ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”.
none ์ด๋ฉด ์‰ผํ‘œ๋ฅผ ๋ถ™์ด์ง€ ์•Š๊ณ , es5 ์ด๋ฉด ๊ฐ์ฒด, ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋  ๋–„ ์‰ผํ‘œ๋ฅผ ๋ถ™์ด๊ณ , all ์ด๋ฉด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉ ํ•  ๋•Œ ์ธ์ž๋ฅผ ์ „๋‹ฌ ํ•  ๋•Œ๋„ ์‰ผํ‘œ๋ฅผ ๋ถ™์ž…๋‹ˆ๋‹ค.

printWidth: ์ค„ ๋ฐ”๊ฟˆํ•  ํญ์˜ ๊ธธ์ด๋ฅผ ์„ค์ •ํ•ด์ค„ ์ˆ˜ ์žˆ์–ด์š”.๐Ÿ“

{
  "arrowParens": "avoid", // ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ๊ด„ํ˜ธ ์‚ฌ์šฉ ๋ฐฉ์‹
  "bracketSpacing": false, // ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์—์„œ ๊ด„ํ˜ธ์— ๊ณต๋ฐฑ ์‚ฝ์ž… ์—ฌ๋ถ€ 
  "endOfLine": "auto", // EoF ๋ฐฉ์‹, OS๋ณ„๋กœ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ๋‹ค๋ฆ„ 
  "htmlWhitespaceSensitivity": "css", // HTML ๊ณต๋ฐฑ ๊ฐ๋„ ์„ค์ •
  "jsxBracketSameLine": false, // JSX์˜ ๋งˆ์ง€๋ง‰ `>`๋ฅผ ๋‹ค์Œ ์ค„๋กœ ๋‚ด๋ฆด์ง€ ์—ฌ๋ถ€ 
  "jsxSingleQuote": false, // JSX์— singe ์ฟผํ…Œ์ด์…˜ ์‚ฌ์šฉ ์—ฌ๋ถ€
  "printWidth": 80, //  ์ค„ ๋ฐ”๊ฟˆ ํ•  ํญ ๊ธธ์ด
  "proseWrap": "preserve", // markdown ํ…์ŠคํŠธ์˜ ์ค„๋ฐ”๊ฟˆ ๋ฐฉ์‹ (v1.8.2)
  "quoteProps": "as-needed" // ๊ฐ์ฒด ์†์„ฑ์— ์ฟผํ…Œ์ด์…˜ ์ ์šฉ ๋ฐฉ์‹
  "semi": true, // ์„ธ๋ฏธ์ฝœ๋ก  ์‚ฌ์šฉ ์—ฌ๋ถ€
  "singleQuote": true, // single ์ฟผํ…Œ์ด์…˜ ์‚ฌ์šฉ ์—ฌ๋ถ€
  "tabWidth": 2, // ํƒญ ๋„ˆ๋น„ 
  "trailingComma": "all", // ์—ฌ๋Ÿฌ ์ค„์„ ์‚ฌ์šฉํ•  ๋•Œ, ํ›„ํ–‰ ์ฝค๋งˆ ์‚ฌ์šฉ ๋ฐฉ์‹
  "useTabs": false, // ํƒญ ์‚ฌ์šฉ ์—ฌ๋ถ€
  "vueIndentScriptAndStyle": true, // Vue ํŒŒ์ผ์˜ script์™€ style ํƒœ๊ทธ์˜ ๋“ค์—ฌ์“ฐ๊ธฐ ์—ฌ๋ถ€ (v1.19.0)
  "parser": '', // ์‚ฌ์šฉํ•  parser๋ฅผ ์ง€์ •, ์ž๋™์œผ๋กœ ์ง€์ •๋จ
  "filepath": '', // parser๋ฅผ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ์„ ์ง€์ •
  "rangeStart": 0, // ํฌ๋งทํŒ…์„ ๋ถ€๋ถ„ ์ ์šฉํ•  ํŒŒ์ผ์˜ ์‹œ์ž‘ ๋ผ์ธ ์ง€์ •
  "rangeEnd": Infinity, // ํฌ๋งทํŒ… ๋ถ€๋ถ„ ์ ์šฉํ•  ํŒŒ์ผ์˜ ๋ ๋ผ์ธ ์ง€์ •,
  "requirePragma": false, // ํŒŒ์ผ ์ƒ๋‹จ์— ๋ฏธ๋ฆฌ ์ •์˜๋œ ์ฃผ์„์„ ์ž‘์„ฑํ•˜๊ณ  Pragma๋กœ ํฌ๋งทํŒ… ์‚ฌ์šฉ ์—ฌ๋ถ€ ์ง€์ • (v1.8.0)
  "insertPragma": false, // ๋ฏธ๋ฆฌ ์ •์˜๋œ @format marker์˜ ์‚ฌ์šฉ ์—ฌ๋ถ€ (v1.8.0)
  "overrides": [ 
    {
      "files": "*.json",
      "options": {
        "printWidth": 200
      }
    }
  ], // ํŠน์ • ํŒŒ์ผ๋ณ„๋กœ ์˜ต์…˜์„ ๋‹ค๋ฅด๊ฒŒ ์ง€์ •ํ•จ, ESLint ๋ฐฉ์‹ ์‚ฌ์šฉ
}

2. ESLint ๋ž€

1. ESLint ๋ž€

ESLint๋Š” ES ์™€ Lint๋ฅผ ํ•ฉ์„ฑ์–ด์ž…๋‹ˆ๋‹ค. ES๋Š” Ecma Script, Lint๋Š” ์—๋Ÿฌ๊ฐ€ ์žˆ๋Š” ์ฝ”๋“œ์— ํ‘œ์‹œ๋ฅผ ๋‹ฌ์•„๋†“๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ, ESLint๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฌธ๋ฒ•์—์„œ ์—๋Ÿฌ๋ฅผ ํ‘œ์‹œํ•ด์ฃผ๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

Lint๋ž€

์œ„ํ‚ค๋ฐฑ๊ณผ์—๋„ lint์— ๋Œ€ํ•œ ์ •์˜๊ฐ€ ์žˆ์–ด ๊ฐ€์ ธ์™”๋‹ค.
Lint๊ฐ€ ๊ผญ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด์—๋งŒ ์ ์šฉ๋˜๋Š” ๋ง์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

๋ฆฐํŠธ(lint) ๋˜๋Š” ๋ฆฐํ„ฐ(linter)๋Š” ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ ์˜ค๋ฅ˜, ๋ฒ„๊ทธ, ์Šคํƒ€์ผ ์˜ค๋ฅ˜, ์˜์‹ฌ์Šค๋Ÿฌ์šด ๊ตฌ์กฐ์ฒด์— ํ‘œ์‹œ(flag)๋ฅผ ๋‹ฌ์•„๋†“๊ธฐ ์œ„ํ•œ ๋„๊ตฌ๋“ค์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ด ์šฉ์–ด๋Š” C ์–ธ์–ด ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” ์œ ๋‹‰์Šค ์œ ํ‹ธ๋ฆฌํ‹ฐ์—์„œ ๊ธฐ์›ํ•œ๋‹ค.
(*์ถœ์ฒ˜: ์œ„ํ‚ค๋ฐฑ๊ณผ)

๋งŽ์€ ์‚ฌ๋žŒ๋“ค๊ณผ ํ˜‘์—…ํ• ๋•Œ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์—๋Ÿฌ์™€ ์ฝ”๋”ฉ ์Šคํƒ€์ผ์„ ์žก์•„์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ์‚ฌ๋žŒ์ด ์ฝ”๋”ฉํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ฉ๋‹ˆ๋‹ค!

2. ์‚ฌ์šฉ๋ฒ•

(1). ์„ค์น˜

$ npm install -D eslint
// or
$ yarn add -D eslint

๊ทผ๋ฐ eslint ์„ค์น˜๋งŒ ํ–ˆ๋‹ค๊ณ  ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฒŒ์•„๋‹ˆ๋ผ extension๋„ ๊ฐ™์ด ์„ค์น˜ํ•ด์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

(2). ์„ค์ •

ESLint์˜ ์„ธ๋ถ€ ์„ค์ •์€ package.json์˜ eslintConfig์—์„œ ํ•ด๋„ ๋˜๊ณ  .eslintrc.js, .eslintrc.json, .eslintrc.yaml, .eslintrc.ymlํŒŒ์ผ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์„œ ํ•  ์ˆ˜ ์žˆ๋‹ค.
์šฐ๋ฆฌ๋Š” root ๋””๋ ‰ํ† ๋ฆฌ์— .eslintrc.jsํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์ž.

2๏ธโƒฃ ESLint ์„ธํŒ…

ํ”„๋กœ์ ํŠธ root์— .eslintrc.json ๋ผ๋Š” ์ด๋ฆ„์˜ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์•„๋ž˜ ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

{
	"extends": "react-app"
}

2๏ธโƒฃ Prettier ์„ค์น˜

Prettier์™€ ESLint๋ฅผ ์—ฐ๊ฒฐ

npm i prettier eslint-config-prettier eslint-plugin-prettier -D

๊ทธ๋ฆฌ๊ณ  .eslintrc.json์˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—…๋ฐ์ดํŠธ

{
	"extends": ["react-app", "plugin:prettier/recommended"]
}

(3). ๋‹ค๋ฅธ๋ฐฉ๋ฒ•

1. default config ์ง€์šฐ๊ธฐ(package.json)
๋” ์ข‹์€ ์„ธํŒ…์„ ํ•˜๊ธฐ์œ„ํ•ด ์•„๋ž˜ ๋ถ€๋ถ„์„ ์ง€์šด๋‹ค.
CRA๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด package.json์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ธํŒ…๋˜์–ด์žˆ์Œ

  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },

2. install eslint

npm install eslint --save-dev

3. setup eslint
npx eslint --init

์ดํ›„ ์„ค์ •๊ณผ์ •์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž…๋ ฅ

4. ํ™•์ธํ•˜๊ธฐ
์œ„์™€ ๊ฐ™์€ ์ ˆ์ฐจ๋ฅผ ๋”ฐ๋ผ์ฃผ๋ฉด ํ•„์š”ํ•œ package๋“ค์ด ์„ค์น˜๋œ๋‹ค.

์„ค์ • ๊ณผ์ •์ด ๋๋‚˜๋ฉด .eslintrc.json ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์€ ๋‚ด์šฉ์ด ์ฑ„์›Œ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

5. ํ”„๋ฆฌํ‹ฐ์–ด ํ•จ๊ป˜ ์‚ฌ์šฉ (ํ”„๋กœํ‹ฐ์–ด ์„ค์น˜์™„๋ฃŒ ํ›„)
Prettier์™€ ESLint๋ฅผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

npm install eslint-plugin-prettier eslint-config-prettier --save-dev

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์˜ ๋‚ด์šฉ์„ .eslintrc ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•œ๋‹ค.

{
  "plugins": ["prettier"],
  "extends": ["eslint:recommended", "plugin:prettier/recommended"],
  "rules": {
    "prettier/prettier": "error"
  }
}

์ถ”๊ฐ€์ •๋ณด

plugins
์šฐ์„  plugin ์ข…๋ฅ˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์žˆ๋Š”๋ฐ, ์˜ˆ๋ฅผ ๋“ค์–ด

eslint-config-airbnb-base: ์—์–ด๋น„์—”๋น„ ๋ฆฐํŠธ ํ”Œ๋Ÿฌ๊ทธ์ธ
eslint-config-next: Next.js ์ „์šฉ ๋ฆฐํŠธ ํ”Œ๋Ÿฌ๊ทธ์ธ
eslint-plugin-react: ๋ฆฌ์•กํŠธ ์ „์šฉ ํ”Œ๋Ÿฌ๊ทธ์ธ
eslint-plugin-react-hooks: React Hooks์˜ ๊ทœ์น™์„ ๊ฐ•์ œํ•ด์ฃผ๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ
eslint-plugin-import: ES2015+์˜ import/export ๊ตฌ๋ฌธ์„ ์ง€์›
eslint-plugin-jsx-a11y: JSX ๋‚ด์˜ ์ ‘๊ทผ์„ฑ ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ฆ‰๊ฐ์ ์ธ AST๋ฆฐํŒ… ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณต
eslint-plugin-prettier: ๋ฆฐํŠธ ์œ„์— ์‚ฌ์šฉํ•  ํ”„๋ฆฌํ‹ฐ์–ด ํ”Œ๋Ÿฌ๊ทธ์ธ
eslint-config-prettier: ์š”๊ฑด ๋ฆฐํŠธ ์„ค์ •๊ณผ ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„์ด ์žˆ์œผ๋ฉด ํ”„๋ฆฌํ‹ฐ์–ด ๋ฃฐ์—์„œ ์ œ์™ธํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ
@typescript-eslint/eslint-plugin: : ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ „์šฉ ๋ฆฐํŠธ

๋Œ€์ถฉ ์ด๋Ÿฌํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ๋“ค์ด ์žˆ๋‹ค. ์ด๊ฒƒ๋“ค ๋ง๊ณ ๋„ ์ข…๋ฅ˜๋Š” ํ›จ์”ฌ ๋งŽ๋‹ค.

ํ”„๋กœ์ ํŠธ์— ํ•„์š”๋กœ ํ•œ ๊ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ npm์ด๋‚˜ yarn์„ ํ†ตํ•ด์„œ ์„ค์น˜ํ•˜๋ฉด ๋œ๋‹ค.

๋งŒ์•ฝ ์œ„์— @typescript-eslint/eslint-plugin์„ ์“ธ ๊ฑฐ๋ฉด, eslintrc ํŒŒ์ผ์˜ plugins ๋ฐฐ์—ด์— ํ•ด๋‹น ๋ชจ๋“ˆ์—์„œ ์ œ๊ณตํ•˜๋Š” @typescript-eslint๋ฅผ ์žฅ์ฐฉ์‹œํ‚ค๋ฉด ๋˜๊ณ , ๋‹ค๋ฅธ ๋ชจ๋“ˆ๋„ ๊ฐ™์ด ์“ธ ๊ฑฐ๋ฉด ๋ฐฐ์—ด์— ๊ฐ™์ด ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฌํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ๋“ค์„ ์‰ฝ๊ฒŒ ์ •๋ฆฌ๋œ airbnb๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ๋ถ„๋Ÿ‰์ด ๋„ˆ๋ฌด ๋งŽ์•„์„œ ์ƒˆ๋กœ์šด 2ํƒ„์œผ๋กœ ๋งŒ๋“ค์–ด์•ผ๊ฒ ๋‹ค..

0๊ฐœ์˜ ๋Œ“๊ธ€