[JS] ESLint ํ ์
#๋ค์ด๊ฐ๋ฉฐ
์์จ๋ณธ ์ฌ๋์ ์์ง๋ง, ํ ๋ฒ๋ง ์จ๋ณธ ์ฌ๋์ ์๋ค๋ ESLint
์ ๋ํด์ ์์๋ณด์.
๊ฐ์ธ ํ๋ก์ ํธ์์๋ ํฌ๊ฒ ํ์์ฑ์ ๋๋ผ์ง ๋ชปํ์ง๋ง, ํ์
ํ๊ฒฝ์์๋ ๊ฐ๋ฐ์๋ค์ ์ฝ๋ฉ ์คํ์ผ์ด ๋ค์ํ๊ธฐ ๋๋ฌธ์
์ฝ๋์ ์ผ๊ด์ฑ์ ์ ์งํ๋ ๊ฒ์ด ์ค์ํ๋ค. ์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ ์ค ํ๋๊ฐ ESLint
๋ค.
Prettier
์ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋ ๊ฐ๋ ฅํ๋ค! ํ์ง๋ง ์ด๋ฒ ํฌ์คํ
์์๋ Prettier
์ ๊ด๋ จ๋ ๋ด์ฉ์ ์๊ณ ESLint
์ ๋ํด์
์ง์ค์ ์ผ๋ก ์์๋ณด๋ ค๊ณ ํ๋ค.
์ฌํ ๋ฆฐํธ๋ฅผ ์ ์ ์ฉํด์ ์ฌ์ฉํด์์ง๋ง ์ด๋ป๊ฒ ๋ฆฐํธ๊ฐ ๋์ํ๋์ง์ ๋ํด ๊ถ๊ธํ๋ ์ฌ๋๋ค์๊ฒ ๋์์ด ๋ ๊ฒ์ด๋ผ ์๊ฐํ๋ค.
#ESLint ๋?
ESLint
ESLint statically analyzes your code to quickly find problems. It is built into most text editors and you can run ESLint as part of your continuous integration pipeline.
ESLint
๋ ์ฝ๋๋ฅผ ์ ์ ์ผ๋ก ๋ถ์ํ์ฌ ๋ฌธ์ ๋ฅผ ๋น ๋ฅด๊ฒ ์ฐพ์๋ด๋ ๋๊ตฌ๋ผ๊ณ ํ๋ค.
ESLint
(์ ์ ๋ถ์ ๋๊ตฌ)๋ ์ฝ๋๋ฅผ ์ ์ ์ผ๋ก ๋ถ์ํด์ ๋ฌธ๋ฒ ์ค๋ฅ๋ ์คํ ๋ฑ์ ์ ์ฌ์ ์๋ฌ๋ฅผ ์ฐพ์๋ด๊ณ , ์ฝ๋ฉ ์ปจ๋ฒค์
๊ฒ์ฆ์ ์๋ํํ ์ ์๋ค. ๋ํํ์ฌ์ธ Airbnb
๋ Naver
๋ฑ ์์๋
์๊ธฐ๋ค์ ESLint
์ค์ ์ ๊ณต๊ฐํด๋๊ธฐ๋ ํ๋ค. ๊ทธ๋งํผ ์ ๋ขฐํ ์ ์๋ ๋๊ตฌ์ด๋ค. ๊ทธ๋ผ ์ด๋ค ๋ฐฉ๋ฒ์ผ๋ก ์ฝ๋๋ฅผ ์ ์ ๋ถ์ํ ์ ์๋ ๊ฑธ๊น? ESLint
๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ตฌ๋ฌธ ๋ถ์๊ธฐ์ธ
Espree๋ฅผ ์ด์ฉํด์ ์ฝ๋๋ฅผ ๋ฌธ์์ด๋ก ์ฝ์ ๋ค ์ฝ๋๋ฅผ ๊ตฌ์กฐํ ํ๋ค. ์ฌ๊ธฐ์ ๊ตฌ์กฐํํ ํธ๋ฆฌ๋ฅผ
AST(Abstract Syntax Tree)๋ผ๊ณ ํ๊ณ , ์ด ํธ๋ฆฌ๋ฅผ ๊ฐ์ง๊ณ ์ฌ๋ฌ๊ฐ์ง eslint rule
๊ณผ ๋์กฐํด์ ๊ฒฝ๊ณ ๋ฅผ ํตํด ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฐ๋ฐ์์๊ฒ ์๋ ค์ค๋ค.
#Espree
Espree
๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ํ์ฑํ๋๊ฑธ๊น? AST Explorer์์ ์ฝ๋๊ฐ ์ด๋ค ํํ๋ก ๊ตฌ์กฐํ ๋๋์ง
์ง์ ๋์ผ๋ก ํ์ธํ ์ ์๋ค. (์ฐ์ธก ๊ฒฐ๊ณผ ํ๋ฉด์์ Tree
ํํ, JSON
ํํ๋ก ํ ๊ธ ํ ์ ์๋ค.)
const a = 1;
const a = 1;
์ด ์ฝ๋๋ฅผ ํ์ฑํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด
{
"type": "Program",
"start": 0,
"end": 12,
"body": [ // ํ๋ก๊ทธ๋จ์ ๋ณธ๋ฌธ์ ๊ตฌ์ฑํ๋ ์์๋ค, ์ง๊ธ์ const a = 1; ํ๋๋ง ์๋ค.
{
"type": "VariableDeclaration",
"start": 0,
"end": 12,
"declarations": [
{
"type": "VariableDeclarator", // ๋ณ์ ์ ์ธ
"start": 6,
"end": 11,
"id": {
"type": "Identifier", // ๋ณ์ ์ด๋ฆ
"start": 6,
"end": 7,
"name": "a" // ๋ณ์ a ๋
},
"init": { // ๋ณ์ ์ด๊ธฐํ
"type": "Literal", // ๋ฆฌํฐ๋ด ๊ฐ
"start": 10,
"end": 11,
"value": 1, // 1์ผ๋ก ์ด๊ธฐํ ๋๋ค.
"raw": "1"
}
}
],
"kind": "const" // ๋ณ์ ์ ์ธ์ ์ข
๋ฅ const์ธ์ง let์ธ์ง var์ธ์ง
}
],
"sourceType": "module"
}
{
"type": "Program",
"start": 0,
"end": 12,
"body": [ // ํ๋ก๊ทธ๋จ์ ๋ณธ๋ฌธ์ ๊ตฌ์ฑํ๋ ์์๋ค, ์ง๊ธ์ const a = 1; ํ๋๋ง ์๋ค.
{
"type": "VariableDeclaration",
"start": 0,
"end": 12,
"declarations": [
{
"type": "VariableDeclarator", // ๋ณ์ ์ ์ธ
"start": 6,
"end": 11,
"id": {
"type": "Identifier", // ๋ณ์ ์ด๋ฆ
"start": 6,
"end": 7,
"name": "a" // ๋ณ์ a ๋
},
"init": { // ๋ณ์ ์ด๊ธฐํ
"type": "Literal", // ๋ฆฌํฐ๋ด ๊ฐ
"start": 10,
"end": 11,
"value": 1, // 1์ผ๋ก ์ด๊ธฐํ ๋๋ค.
"raw": "1"
}
}
],
"kind": "const" // ๋ณ์ ์ ์ธ์ ์ข
๋ฅ const์ธ์ง let์ธ์ง var์ธ์ง
}
],
"sourceType": "module"
}
๊ฐ๋จํ๊ฒ ๋ณ์ a์ 1์ ํ ๋นํ๋ ์ฝ๋์์๋ ๊ต์ฅํ ์์ธํ๊ณ ๋ค์ํ ์ ๋ณด๊ฐ ๋ด๊ฒจ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ฝ๋์ ์์์ ๊ณผ ๋, ๋ณ์์ธ์ง ํจ์์ธ์ง(ํ์ดํ ํจ์์ธ์ง) ๋ฑ๋ฑ ์์ฃผ ์์ธํ ์ ๋ณด๊ฐ ๋ด๊ฒจ์๋ค. ํ์
์คํฌ๋ฆฝํธ์ธ ๊ฒฝ์ฐ์๋ espree
๊ธฐ๋ฐ ํ์๊ฐ ์กด์ฌํด์,
๋ถ์ํ ์ ์๋ค. AST Explorer
์์ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณด๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๊ตฌ์กฐํ ํ์ ๋ ๋์จ ๊ฒฐ๊ณผ์ ๋ํด์ type
์ ๊ดํ ์ ๋ณด๋ ์ถ๊ฐ์ ์ผ๋ก ๊ฒฐ๊ณผ์ ๋ณด์ฌ์ง๋ค.
ESLint
๋ ์ด espree
๊ฐ ์ฝ๋๋ฅผ ๋ถ์ํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ง๊ณ ๊ฒ์ฌ๋ฅผ ์ํํ๊ณ , ์ง์ ํด๋์ ๊ท์น์ ๋ฐ๋ผ ์ด๋๊ฐ ์๋ชป๋๋์ง ๊ทธ๋ฆฌ๊ณ ์ด๋ป๊ฒ ์์ ํด์ผํ๋ ์ง ๊ฐ์ ๋ฐฉ๋ฒ์ ์ ์ํด์ค๋ค.
์ด ๊ท์น์ ๋ํด์ ์์๋ณด์.
#ESLint Plugin๊ณผ Config
ESLint ์ค์ ์ ํ ๋ eslint-plugin-
์ด๋ eslint-config-
์ผ๋ก ์์ํ๋ ๋ค์ํ npm ํจํค์ง๊ฐ ์กด์ฌํ๋ค. plugin
๊ณผ config
์ ์ญํ ๊ณผ ์ฐจ์ด์ ์ ์ดํด๋ณด์.
Plugin
ํ๋ฌ๊ทธ์ธ์ ์๋ก์ด ๊ท์น๋ค์ ESLint
์ ์ถ๊ฐํ๋ค. ์ด๋ฐ ํ๋ฌ๊ทธ์ธ๋ค์ ํน์ ํ๋ก๊ทธ๋๋ฐ ํจํด, ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ํ๋ ์์ํฌ์ ๋ํ ์ถ๊ฐ์ ์ธ ๊ฒ์ฌ ๊ท์น์ ์ ๊ณตํ๋ค.
์๋ฅผ ๋ค์ด eslint-plugin-react
๋ useEffect
์ ์์กด์ฑ ๋ฐฐ์ด์ ์ฒดํฌํด์ฃผ๊ฑฐ๋, ์ปดํฌ๋ํธ์ key
์์ฑ์ ์ฃผ์ง ์์ ๊ฒฝ์ฐ ๋ฑ ๋ค์ํ ๋ถ๋ถ์ ์ฒดํฌํด์ค๋ค.
Config
Config๋ก ์์ํ๋ ํจํค์ง๋ ์์ ๋งํ๋ Plugin
๋ค๊ณผ rules
๋ฅผ ๋ฌถ์ด์ ์ ๊ณตํ๋ ์ค์ ํ์ผ๋ก ์๊ฐํ๋ฉด ๋๋ค. ๋ํ์ ์ผ๋ก eslint-config-airbnb
, eslint-config-prettier
, eslint-config-naver
๋ฑ ๋ค์ํ ํจํค์ง๊ฐ ์กด์ฌํ๋ค.
.eslintrc ์ค์ ํ์ผ์์
.eslintrc ์ค์ ํ์ผ์์ extends
๋ ๋ค๋ฅธ ์ค์ ํ์ผ์ ์์(extends)๋ฐ์์ ์ฌ์ฉํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค. plugins
๋ ์ถ๊ฐ์ ์ธ ๊ท์น์ด๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ํ๋ฌ๊ทธ์ธ์ ์ถ๊ฐํ ๋ ์ฌ์ฉ๋๋ค.
rules
์๋ ๊ทธ ํ๋ฌ๊ทธ์ธ์ ์ด๊ฒผ์ ๋ ๋์ํ๊ณ ํ๊ฑธ ์
๋ ฅํด์ฃผ๋ฉด ๋๋ค.(ํ์ฑํ, ๋นํ์ฑํ, ์๋ฌ, ๊ฒฝ๊ณ ๋ฑ๋ฑ)
#๋๋ง์ Custom ESLint Rule ๋ง๋ค๊ธฐ
ํ๋ก์ ํธ๋ฅผ ์งํํ๋ค๋ณด๋ฉด, ํ ๋ด์์ ์ฝ๋ฉ ์ปจ๋ฒค์
์ ์ ์งํ๋ ๊ฒ์ด ์ค์ํ๋ค. ๊ทธ๊ฑธ ์ํด์ ESLint
์ ๋์์ ๋ฐ๋๋ฐ, ๊ฐ๋ ํ์ด ์ ํ ํน์ ํ ๊ท์น์ ์ฝ๋์ ๋ฐ์ํ๊ณ ์ถ์ด๋ ๊ธฐ์กด์ ์ ๊ณต๋๋
ESLint
์ค์ ์ด๋ ํ๋ฌ๊ทธ์ธ์ผ๋ก๋ ์ถฉ๋ถํ ๋์ํ ์ ์๋ ์ํฉ์ด ๋ฐ์ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ์ด ๋, ์ฌ์ฉ์๊ฐ ์ง์ ๊ท์น์ ๋ง๋ค์ด์ ์ ์ฉํ ์ ์๋ค. ์ด๋ฏธ ์กด์ฌํ๋ ๊ท์น์ ์ปค์คํฐ๋ง์ด์ง ํด์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ
์์ ์๋ก์ด ๊ท์น์ ๋ง๋๋ ๋ฐฉ๋ฒ์ด ์๋๋ฐ ์ฌ๊ธฐ์๋ ํ์์ ๋ฐฉ๋ฒ์ ์์๋ก ๋ค์ด์ ์ค๋ช
ํ๋ค.
์๋ฅผ ๋ค์ด ๋ณ์์ ๊ธธ์ด๋ ์ต์ 2๊ธ์ ์ด์๋ง ํ์ฉํ๊ณ ์ถ์ ESLint
๊ท์น์ ์์ฑํ๋ค๊ณ ํด๋ณด์. ๊ท์น์ ์์ฑํ๊ธฐ ์ํด์๋
๋จผ์ ๋ณ์๋ฅผ ์ ์ธํ์ ๋, AST
๊ฐ ์ด๋ป๊ฒ ์์ฑ๋๋ ์ง ํ์ธํด์ผํ๋ค.
const a = "1234"
const a = "1234"
๋ณ์๋ช ์ ๊ธธ์ด๊ฐ 1์ธ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
{
"type": "Program",
"start": 0,
"end": 17,
"range": [
0,
17
],
"body": [
{
"type": "VariableDeclaration", // 1) ๋ณ์์ ์ธ ์ ์ฒด๋ฅผ ๋ํ๋
"start": 0,
"end": 17,
"range": [
0,
17
],
"declarations": [ // 2) ๋ณ์ ์ ์ธ ๋ชฉ๋ก
{
"type": "VariableDeclarator", // 3) const๋ฅผ ์ ์ธํ a = "1234";
"start": 6,
"end": 16,
"range": [
6,
16
],
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"range": [
6,
7
],
"name": "a" // 4) ์ฐ๋ฆฌ๊ฐ ํ์ํ ๊ฒ
},
"init": {
"type": "Literal",
"start": 10,
"end": 16,
"range": [
10,
16
],
"value": "1234",
"raw": "\"1234\""
}
}
],
"kind": "const"
}
],
"sourceType": "module"
}
{
"type": "Program",
"start": 0,
"end": 17,
"range": [
0,
17
],
"body": [
{
"type": "VariableDeclaration", // 1) ๋ณ์์ ์ธ ์ ์ฒด๋ฅผ ๋ํ๋
"start": 0,
"end": 17,
"range": [
0,
17
],
"declarations": [ // 2) ๋ณ์ ์ ์ธ ๋ชฉ๋ก
{
"type": "VariableDeclarator", // 3) const๋ฅผ ์ ์ธํ a = "1234";
"start": 6,
"end": 16,
"range": [
6,
16
],
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"range": [
6,
7
],
"name": "a" // 4) ์ฐ๋ฆฌ๊ฐ ํ์ํ ๊ฒ
},
"init": {
"type": "Literal",
"start": 10,
"end": 16,
"range": [
10,
16
],
"value": "1234",
"raw": "\"1234\""
}
}
],
"kind": "const"
}
],
"sourceType": "module"
}
- VariableDeclaration: ๋ณ์ ์ ์ธ ์ ์ฒด๋ฅผ ๋ํ๋ธ๋ค.
const a = "1234"
const a = "1234"
- declarations: ๋ณ์ ์ ์ธ ๋ชฉ๋ก์ ๋ํ๋ธ๋ค. ์ฌ๊ธฐ์๋
const a = "1234"
const a = "1234"
๋ผ์ ๋ฐฐ์ด์ ํ๋๋ฐ์ ์์ง๋ง,const a = "1234", b = "56";
const a = "1234", b = "56";
์ด๋ฐ ์์ผ๋ก ์ ์ธํ๋ฉดdeclarations
๋ฐฐ์ด์ ์์๊ฐ ์ถ๊ฐ๋๋ค. - VariableDeclarator:
const
๋ฅผ ์ ์ธํa = "1234"
a = "1234"
๋ถ๋ถ์ ์๋ฏธํ๋ค. - name: ๋ณ์๋ช
์ ์๋ฏธํ๋๋ฐ, ์ฐ๋ฆฌ๋ ์ด
name
์ ๊ธธ์ด๋ฅผ ์ฒดํฌํด์ 2๋ณด๋ค ์๋ค๋ฉด ๊ฒฝ๊ณ ๋ฅผ ํด์ฃผ๋ ๋ฆฐํธ ๋ฃฐ์ ์์ฑํ ์ ์์ ๊ฒ์ด๋ค.
#ESLint Rule(Plugin) ํ๋ก์ ํธ ์์ฑํ๊ธฐ
ESLint ๊ท์น์ ์์ฑํ๊ธฐ ์ํด, ์ฑ ํ๋ก์ ํธ์ ๋ณ๊ฐ๋ก ํ๋ฌ๊ทธ์ธ ํ๋ก์ ํธ๋ฅผ ์์ฑํด์ผํ๋ค. ํ๋ฌ๊ทธ์ธ์ ๋ฌด์กฐ๊ฑด eslint-plugin-
์ผ๋ก ์์ํด์ผ ํ๊ธฐ ๋๋ฌธ์
์ปจ๋ฒค์
์ ๋ง์ถฐ์ ์์ฑํด์ฃผ์.
mkdir eslint-plugin-my
cd eslint-plugin-my
npm init --y
touch index.js
mkdir eslint-plugin-my
cd eslint-plugin-my
npm init --y
touch index.js
index.jx
ํ์ผ์ ์์ฑํ๊ณ ๊ท์น์ ์์ฑํ๋ค.
module.exports.rules = {
// ... meta ํ๋
// ๋ฃฐ ์ด๋ฆ์ ์ ์ธํ๋ค.
"variable-length": {
create: function (context) {
return {
// VariableDeclarator ๋
ธ๋๊ฐ ๋ฐ๊ฒฌ๋ ๋ ์คํ๋๋ ํจ์
VariableDeclarator: (node) => {
// node.id.name์ ๋ณ์์ ์ด๋ฆ์ ๊ฐ์ง๊ณ ์๋ค. (์์ชฝ json ์ฐธ๊ณ )
// ์ฌ๊ธฐ์๋ ๋ณ์ ์ด๋ฆ์ ๊ธธ์ด๋ฅผ ๊ฒ์ฌํฉ๋๋ค.
if (node.id.name.length < 2) {
context.report({
node,
message: "Variable names should be longer than 1 character"
});
}
}
};
}
}
};
module.exports.rules = {
// ... meta ํ๋
// ๋ฃฐ ์ด๋ฆ์ ์ ์ธํ๋ค.
"variable-length": {
create: function (context) {
return {
// VariableDeclarator ๋
ธ๋๊ฐ ๋ฐ๊ฒฌ๋ ๋ ์คํ๋๋ ํจ์
VariableDeclarator: (node) => {
// node.id.name์ ๋ณ์์ ์ด๋ฆ์ ๊ฐ์ง๊ณ ์๋ค. (์์ชฝ json ์ฐธ๊ณ )
// ์ฌ๊ธฐ์๋ ๋ณ์ ์ด๋ฆ์ ๊ธธ์ด๋ฅผ ๊ฒ์ฌํฉ๋๋ค.
if (node.id.name.length < 2) {
context.report({
node,
message: "Variable names should be longer than 1 character"
});
}
}
};
}
}
};
์๋ตํ meta
ํ๋๋ ๋ฃฐ์ ๋ํ ์ ๋ณด๋ฅผ ๋ํ๋ด๋ ํ๋๋ค. ์ค์ ๋ก ๊ท์น์ด ๋์ํ๊ธฐ ์ํ ์ฝ๋์๋ ๊ด๋ จ์ด ์๊ธฐ ๋๋ฌธ์ ์๋ตํ๋ค.
create
ํจ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. ์ด ๊ฐ์ฒด์์๋ ์ฝ๋ ์ค๋ฉ์ ๊ฐ์งํ ์ ํ์๋ ์ด๋ฒคํธ๋ช
์ ์ ์ธํ ์ ์๋ค. ์ด ์ฝ๋์ ํต์ฌ์
VariableDeclarator
๋
ธ๋์ ๋ํ ์ฝ๋ฐฑํจ์์ธ๋ฐ ์ด ํจ์๋ ๊ฐ ๋ณ์ ์ ์ธ์ ๋
ธ๋(VariableDeclarator
)๊ฐ ๋ฐ๊ฒฌ๋ ๋ ๋ง๋ค ํธ์ถ๋๋ค.
ํจ์ ๋ด๋ถ์์๋ node.id.name
์ ํตํด ๋ณ์ ์ด๋ฆ์ ์ ๊ทผํ๊ณ , ์ด ์ด๋ฆ์ ๊ธธ์ด๊ฐ 2๋ณด๋ค ์์์ง ๊ฒ์ฌํ๋ค. ๋ง์ฝ ์๋ค๋ฉด
context.report
๋ฉ์๋๋ก ESLint
์๊ฒ ๊ฒฝ๊ณ ๋ฅผ ๋ณด๊ณ ํ๋ค.
๋ง์ฝ meta
ํ๋์์ ๋ฉ์ธ์ง๋ฅผ ์์ฑํด๋จ๋ค๋ฉด meta.messages
๊ฐ์ ธ์ฌ messageId
๋ฅผ report
์ ์ ๋ฌํด์ฃผ๋ฉด ๊ทธ ๋ฉ์ธ์ง๋ฅผ ์ฌ์ฉํ ์ ๋ ์๊ณ ,
fix
๋ฅผ ํตํด์ ์๋์ผ๋ก ์์ ํ ์ ์๋ ์ฝ๋๋ฅผ ๋ฃ์ด ์ค ์๋ ์๋ค. (์, useEffect
์ ์์กด์ฑ ๋ฐฐ์ด์ ์๋์ผ๋ก ๋ฃ์ด์ฃผ๋ ๊ทธ๋ฐ ์ฝ๋)
#์ฑ์ ์ปค์คํ ๊ท์น ์ ์ฉํ๊ธฐ
ํ๋ฌ๊ทธ์ธ ํ๋ก์ ํธ๋ฅผ ์์ฑํ์ผ๋ ์ฑ ํ๋ก์ ํธ๋ก ๋์๊ฐ์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ๋ฆฐํธ ๊ท์น์ ์ ์ฉํด๋ณด์.
ํ๋ฌ๊ทธ์ธ์ ์ฐ๋ฆฌ ํ๋ก์ ํธ์์ ์ ์ฉํ๊ธฐ ์ํด์๋ ํ๋ฌ๊ทธ์ธ ํ๋ก์ ํธ๋ฅผ npm์ ๋ฑ๋กํ๊ณ , ์ฑ์์ ์ค์นํด์ผ ํ๋๋ฐ ํ๋ฌ๊ทธ์ธ์ publish ํ์ง ์๊ณ ๋ก์ปฌ์์ ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ๋ ์๋ค.
ํ๋ฌ๊ทธ์ธ ํ๋ก์ ํธ์์ ์๋์ ๋ช ๋ น์ด๋ก ๋งํฌ๋ฅผ ์์ฑํ๋ค.
cd eslint-plugin-my
npm link
cd eslint-plugin-my
npm link
๊ทธ ๋ค์ ์ฑ ํ๋ก์ ํธ์์ ์ฐ๊ฒฐํด์ฃผ์
cd my-app
npm link eslint-plugin-my
cd my-app
npm link eslint-plugin-my
์ฐ๊ฒฐ์ด ์ ๋๋ค๋ฉด, ์ฑ ํ๋ก์ ํธ์ ESLint
์ค์ ํ์ผ์์
module.exports = {
// ...
plugins: ['react-refresh', 'my'], // <-
rules: {
'react-refresh/only-export-components': [
'warn',
{allowConstantExport: true},
],
'react/prop-types': 'warn',
'my/variable-length': 'warn' // <-
}
};
module.exports = {
// ...
plugins: ['react-refresh', 'my'], // <-
rules: {
'react-refresh/only-export-components': [
'warn',
{allowConstantExport: true},
],
'react/prop-types': 'warn',
'my/variable-length': 'warn' // <-
}
};
ํ๋ฌ๊ทธ์ธ ๋ฐฐ์ด์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ eslint-plugin-my
์์์ my
๋ฅผ ์
๋ ฅํ๊ณ , rules
๋ฅผ ์ค์ ํ ๋, ์ฐ๋ฆฌ my(rules)
๋ด๋ถ์ variable-length
๋ฅผ ์ด๋ป๊ฒ ์ ์ดํ ๊ฒ์ธ์ง ์์ฑํด์ฃผ๋ฉด ๋๋ค.
์ด์ ์ฑ์์ const a = 1;
const a = 1;
์ฒ๋ผ ๋ณ์๋ช
์ด ํ ๊ธ์๋ผ๋ฉด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ์์ํฌ ๊ฒ์ด๋ค.
map((_, index) => ) ์ฒ๋ผ `_`๋ ์ ์ธํ๊ณ ์ถ์ ๊ฒฝ์ฐ
module.exports = {
'var-length': (context) => ({
VariableDeclarator: (node) => {
const { options } = context
const allowedList = options.find((opt) => 'allowed' in opt)
const allowed = allowedList.allowed || []
if (node.id.name.length < 2 && !allowed.includes(node.id.name)) { // ์กฐ๊ฑด ์ถ๊ฐ
context.report(
node,
`Variable names should be longer than 1 character ${node.type}`,
)
}
},
}),
},
}
module.exports = {
'var-length': (context) => ({
VariableDeclarator: (node) => {
const { options } = context
const allowedList = options.find((opt) => 'allowed' in opt)
const allowed = allowedList.allowed || []
if (node.id.name.length < 2 && !allowed.includes(node.id.name)) { // ์กฐ๊ฑด ์ถ๊ฐ
context.report(
node,
`Variable names should be longer than 1 character ${node.type}`,
)
}
},
}),
},
}
module.exports = {
// ...
rules: {
// ...
{allowConstantExport: true},
],
'react/prop-types': 'warn',
'my/variable-length': ['warn', { allowed: ['_'] }] // <-
}
};
module.exports = {
// ...
rules: {
// ...
{allowConstantExport: true},
],
'react/prop-types': 'warn',
'my/variable-length': ['warn', { allowed: ['_'] }] // <-
}
};
#๋ง์น๋ฉฐ
๊ทธ๋ฅ ์์ด๋น์๋น ๋๋ ค๋ฐ๊ณ rules
๊ฒ์ํด์ warn
์ผ๋ก ๋ฐ๊ฟ๊ฐ๋ฉด์ ESLint
๋ฅผ ์ฌ์ฉํ์์ง๋ง, ์ด๋ฒ ํฌ์คํ
์ ์์ฑํ๋ฉด์
๋จ์ํ ๊ท์น์ ์ ์ฉํ๋ ๊ฒ์ ๋์ด์, ๊ทธ ๊ท์น๋ค์ด ์ ์ค์ํ๊ณ ์ด๋ป๊ฒ ์๋ํ๋์ง๋ฅผ ์ดํดํ๊ฒ ๋์๋ค.