๐ŸŽ‰ berenickt ๋ธ”๋กœ๊ทธ์— ์˜จ ๊ฑธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐ŸŽ‰
Lang
JavaScript
21-ESLint & Prettier

1. ESLint

์˜ค๋ž˜๋œ ์Šค์›จํ„ฐ์˜ ๋ณดํ‘ธ๋ผ๊ธฐ๊ฐ™์€ ๊ฒƒ์„ ์˜์–ด๋กœ ๋ฆฐํŠธ(Lint)๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ๋ณดํ‘ธ๋ผ๊ธฐ๊ฐ€ ๋งŽ์œผ๋ฉด ์˜ท์ด ๋ณด๊ธฐ์— ์˜ˆ์˜์ง€ ์•Š์€๋ฐ ์ฝ”๋“œ์—๋„ ์ด๋Ÿฐ ๋ณดํ”„๋ผ๊ธฐ์ฒ˜๋Ÿผ ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ๋งž์ถ”์ง€ ์•Š์€ ๊ฒฝ์šฐ, ์„ ์–ธํ•œ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋“ฑ ๋ณด๊ธฐ์— ์˜ˆ์˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ณดํ‘ธ๋ผ๊ธฐ๊ฐ€ ์žˆ๋Š” ์˜ท์„ ์ž…์„ ์ˆ˜๋Š” ์žˆ๋“ฏ์ด ์ด๋Ÿฐ ์ฝ”๋“œ๋กœ ๋งŒ๋“  ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๋„ ๋™์ž‘์€ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๊ณ  ์ ์  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ๊ฐ€ ํž˜๋“ค์–ด ์ง‘๋‹ˆ๋‹ค. ๋ณดํ‘ธ๋ผ๊ธฐ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” Lint roller์ฒ˜๋Ÿผ ์ฝ”๋“œ์˜ ์˜ค๋ฅ˜๋‚˜ ๋ฒ„๊ทธ, ์Šคํƒ€์ผ ๋”ฐ์œ„๋ฅผ ์ ๊ฒ€ํ•˜๋Š” ๊ฒƒ์„ ๋ฆฐํŠธ(Lint) ํ˜น์€ ๋ฆฐํ„ฐ(Linter)๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

  • https://eslint.org/docs/latest/rules/
  • ๊ฐœ๋ฐœ์ž๋“ค์ด ํŠน์ •ํ•œ ๊ทœ์น™์„ ๊ฐ€์ง€๊ณ  ์ฝ”๋“œ๋ฅผ ์งค์ˆ˜์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ์ฃผ์š” ๊ธฐ๋Šฅ
    • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์“ฐ๋Š” ๊ฐ€์ด๋“œ ๋ผ์ธ ์ œ์‹œ ๋“ฑ ํฌ๋งทํ„ฐ(formatter) ์—ญํ• ๋„ ํ•˜์ง€๋งŒ
    • ์ฃผ์š” ๊ธฐ๋Šฅ์€ ๋ฌธ๋ฒ• ์˜ค๋ฅ˜ ์žก๋Š” ๊ฒƒ
1
$ npm i eslint # eslint ์„ค์น˜
2
$ touch .eslintrc.js # .eslintrc.js ์ƒ์„ฑ
3
$ npm run lint # ๋ฆฐํŠธ ์‹คํ–‰

๊ทœ์น™์„ ์ฐพ์•„์„œ .eslintrc.js์— ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

1
// .eslintrc.js
2
module.exports = {
3
extends: ['eslint:recommended'],
4
}

2. Prettier

  • ์ฝ”๋“œ ํ˜•์‹์„ ๋งž์ถ”๋Š”๋ฐ ์‚ฌ ์šฉ ์ž‘์€๋”ฐ์˜ดํ‘œ(โ€˜)๋ฅผ ์‚ฌ์šฉํ• ์ง€ ํฐ ๋”ฐ ์˜ดํ‘œ(โ€œ)๋ฅผ ์‚ฌ์šฉํ• ์ง€,
  • Indent ๊ฐ’์„ 2๋กœ ์ค„์ง€ 4๋กœ ์ค„์ง€๋“ฑ๋“ฑ, ์—๋Ÿฌ ์ฐพ๋Š”๊ฒƒ์ด ์•„๋‹Œ ์ฝ”๋“œ ํฌ๋งทํ„ฐ ์—ญํ• 
1
$ npm i prettier # prettier ์„ค์น˜
2
$ npx prettier src/**/* --write # prettier ์‹คํ–‰

์•„๋‹ˆ๋ฉด VSCode ํ™•์žฅ ๊ธฐ๋Šฅ ์‚ฌ์šฉ

  • ํ™•์žฅ ๊ธฐ๋Šฅ์€ ํ˜ผ์ž ์‚ฌ์šฉํ•  ๋–„ ์ข‹์Œ
  • npm์œผ๋กœ ์„ค์น˜๋Š” ์—ฌ๋Ÿฌ ๊ฐœ๋ฐœ์ž์™€ ๊ฐ™์€ ํฌ๋งท์„ ์œ ์ง€ํ•  ๋–„ ์‚ฌ์šฉ

2.1 ์˜ต์…˜


3. ESLint + Prettier ํ†ตํ•ฉ

Prettier๋Š” Eslint์™€ ํ†ตํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์„œ๋กœ ์ถฉ๋Œํ•˜๋Š” ์˜ต์…˜์ด ์žˆ์œผ๋ฉด ํ”„๋ฆฌํ‹ฐ์–ด ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜๋Œ๊ณ  ํ•˜๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

1
$ npm i eslint-config-prettier eslint-plugin-prettier

์„ค์ • ํŒŒ์ผ์„ eslint์— ์ถ”๊ฐ€

1
// .eslintrc.js
2
module.exports = {
3
extends: ['eslint:recommended'],
4
}

4. ๋ช…๋ น์–ด ์ž๋™ํ™”

  1. Git Hook์œผ๋กœ ์ž๋™ํ™”
  2. ์—๋””ํ„ฐ ํ™•์žฅ ๊ธฐ๋Šฅ์œผ๋กœ ์ž๋™ํ™”

4.1 ์—๋””ํ„ฐ ํ™•์žฅ ๊ธฐ๋Šฅ์œผ๋กœ ์ž๋™ํ™”โญ

  1. VSCode ์—๋””ํ„ฐ์˜ ํ™•์ง•๊ธฐ๋Šฅ(Estention)์˜ Eslint, Prettier ํ™•์žฅ ๊ธฐ๋Šฅ ์„ค์น˜
  2. setting.json ์„ค์ • ํŒŒ์ผ๋กœ ๊ฐ€์„œ eslint๋ฅผ ํ™œ์„ฑํ™”
1
// VSCode setting.json
2
{
3
"eslint.enable": true, // eslint ํ™œ์„ฑํ™”
4
"editor.codeActionsOnSave": {
5
// ์ €์žฅํ•  ๋–„๋งˆ๋‹ค eslint ์ฝ”๋“œ ๊ณ ์น˜๊ธฐ
6
"source.fixAll.eslint": true
7
}
8
}

5. ์„ค์ • ํŒŒ์ผ ์“ฐ๋Š” ์˜ต์…˜ ์ •๋ฆฌ

5.1 VSCode setting.json์„ค์ •

1
{
2
/* ESLint, Prettier ์–ธ์–ด๋ณ„ ์„ค์ • */
3
"eslint.enable": true,
4
"editor.codeActionsOnSave": {
5
"source.fixAll.eslint": true
6
},
7
"prettier.singleQuote": true,
8
"editor.formatOnSave": false,
9
"editor.defaultFormatter": "esbenp.prettier-vscode",
10
"[html]": {
11
"editor.formatOnSave": true,
12
"editor.defaultFormatter": "vscode.html-language-features"
13
},
14
"[javascript]": {
15
"editor.formatOnSave": true
16
},
17
// jsx
18
"[javascriptreact]": {
19
"editor.formatOnSave": true
20
},
21
"[typescript]": {
22
"editor.formatOnSave": true
23
}
24
// ์œ„ ์–ธ์–ด๋“ค ์™ธ์—๋„ ์ €์žฅ ์‹œ ESLint, Prettier ์ ์šฉํ•  ์–ธ์–ด๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.
25
}

5.2 .prettierrc.json

1
{
2
"singleQuote": true,
3
"bracketSpacing": true,
4
"bracketSameLine": true,
5
"arrowParens": "avoid",
6
"printWidth": 120
7
}

5.3 .eslintrc.json

1
{
2
"parserOptions": {
3
"ecmaVersion": "latest"
4
},
5
"env": {
6
"browser": true,
7
"node": true,
8
"commonjs": true,
9
"es2022": true
10
},
11
"globals": { "_": true },
12
"plugins": ["import", "html"],
13
"extends": "airbnb-base",
14
"rules": {
15
// "off" or 0 - turn the rule off
16
// "warn" or 1 - turn the rule on as a warning (doesnโ€™t affect exit code)
17
// "error" or 2 - turn the rule on as an error (exit code is 1 when triggered)
18
// "no-var": "off",
19
"no-console": "warn",
20
"no-plusplus": "off",
21
"no-shadow": "off",
22
"vars-on-top": "off",
23
"no-underscore-dangle": "off", // var _foo;
24
"comma-dangle": "off",
25
"func-names": "off", // setTimeout(function () {}, 0);
26
"prefer-template": "off",
27
"no-nested-ternary": "off",
28
"max-classes-per-file": "off",
29
"consistent-return": "off",
30
"no-restricted-syntax": ["off", "ForOfStatement"], // disallow specified syntax(ex. WithStatement)
31
"prefer-arrow-callback": "error", // Require using arrow functions for callbacks
32
"require-await": "error",
33
"arrow-parens": ["error", "as-needed"], // a => {}
34
"no-param-reassign": ["error", { "props": false }],
35
"no-unused-expressions": [
36
"error",
37
{
38
"allowTernary": true, // a || b
39
"allowShortCircuit": true, // a ? b : 0
40
"allowTaggedTemplates": true
41
}
42
],
43
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
44
"max-len": [
45
"error",
46
{
47
"code": 120,
48
"ignoreComments": true,
49
"ignoreStrings": true,
50
"ignoreTemplateLiterals": true
51
}
52
] // prettier์˜ printWidth ์˜ต์…˜ ๋Œ€์‹  ์‚ฌ์šฉ
53
}
54
}