[초기세팅] ESLint, Prettier, Stylelint 설치
ESLINT란?
코딩 컨벤션에 위배되는 코드나 안티 패턴을 자동 검출하는 정적 코드 분석 도구로 개발자가 자신의 스타일 가이드를 작성하며 일정한 코딩 퀄리티를 보장할 수 있도록 하는 툴이다.
[VSCode Eslint 확장 설치]

[yarn에 eslint add]
yarn add -D eslint[eslint 패키치 추가]
yarn add -D eslint eslint-config-prettier eslint-plugin-prettier eslint-plugin-import
eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-simple-import-sort
@typescript-eslint/eslint-plugin @typescript-eslint/parsereslint-config-prettier
: prettier 설정과 충돌하는 eslint 규칙 비활성화
eslint-plugin-prettier
: eslint 내 prettier 검사 실행
eslint-plugin-import
: import/export 문법의 린팅을 지원하고 파일 경로, import 이름의 오타 예방
eslint-plugin-react
: 리액트와 관련된 룰을 정의
eslint-plugin-react-hooks
: 리액트 훅과 관련된 룰을 정의
eslint-plugin-simple-import-sort
: 자동으로 import문 정렬
@typescript-eslint/eslint-plugin @typescript-eslint/parser
: 타입스크립트 코드 린팅해 주는 도구
[.eslintrc.json 파일 추가]
{
"env": {
"browser": true,
"es2021": true,
"node": true,
"es6": true
},
"plugins": [
"react",
"react-hooks",
"@typescript-eslint",
"@typescript-eslint/eslint-plugin",
"simple-import-sort",
"prettier",
"import"
],
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"plugin:prettier/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
],
"rules": {
"quotes": ["off", "single"],
"semi": ["error", "always"],
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0 }],
"no-multi-spaces": "error",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "off",
"react/react-in-jsx-scope": "off",
"arrow-parens": ["error", "always"],
"no-duplicate-imports": "error",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"no-unused-vars": "error",
"no-undef": "error",
"indent": "off",
"import/no-unresolved": "off",
"no-console": ["warn", { "allow": ["warn", "error", "info"] }],
"prettier/prettier": "error",
"import/order": [
"error",
{
"groups": [["builtin", "external"], "internal", ["parent", "sibling"], "index"],
"pathGroups": [
{
"pattern": "react*",
"group": "external",
"position": "before"
}
],
"alphabetize": {
"order": "asc",
"caseInsensitive": true
}
}
]
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"ignorePatterns": ["build", "dist", "public"],
"settings": {
"import/resolver": {
"node": {
"moduleDirectory": ["node_modules", "src/"],
"extensions": [".js", ".jsx", ".ts", ".tsx", ".d.ts", ".svg"]
}
},
"react": {
"version": "detect"
},
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx", ".js"]
}
}
}[.eslintrc 규칙 설정]
quotes: 쌍따옴표가 아닌 홑따옴표 사용
semi: semi colon을 강제
no-multiple-empty-lines/no-multi-spaces: 빈 라인/스페이스 여러개 금지
react-hooks/rules-of-hooks: 리액트 훅의 순서 지정
arrow-parens: 화살표 함수 괄호 사용 방식
arrow-function 인자가 2개 이상이면 괄호 필수
no-duplicate-imports: 중복 Import 금지
simple-import-sort/imports: import 정렬 강제
simple-import-sort/exports: export 정렬 강제
no-unused-vars: 사용하지 않는 변수 에러 처리
no-undef: 정의 안 한 변수 사용 금지
indent: 프리티어 충돌 방지
import/no-unresolved: 타입스크립트에서 경로를 제대로 잡지 못할 때 사용
no-console: 콘솔은 확인 뒤 삭제
prettier/prettier: error ESLint 내 Prettier를 실행 규칙
Prettier란?
코드 구현과는 관련없는, 일관된 텍스트 작성을 도와주는 도구로 탭의 줄 간격이나, 줄바꿈 정도 등 텍스트 작성에 관련하여 프로젝트 내 일관된 형식을 가지게 한다.
[VSCode Prettier 확장 설치]

yarn에 Prettier add
yarn add -D prettierprettier 이 잘 적용되지 않는다면 crtml+` 를 들어가 아래 설정을 nont->code prettier로 바꿔주면 된다!

[.prettierrc 파일 추가] (추가하지 않을 시 prettier root에 있는 기본 설정으로 들어감)
{
"printWidth": 120,
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"requirePragma": false,
"arrowParens": "always",
"bracketSameLine": true,
"endOfLine": "auto"
}[.prettierrc 설정 목록 ]
printWidth: 줄 바꿈 폭 길이
semi: 세미콜론 사용 여부
trailingComma: 후행 콤마 사용 방식
requirePragma: 파일 상단에 미리 정의된 주석을 작성 및 Pragma 포맷팅 사용 여부 지정
arrowParens: 화살표 함수 괄호 사용 방식
bracketSpacing: 객체 리터럴에서 괄호에 공백 삽입 여부
endOfLine: 텍스트의 한 줄이 끝남을 표시하는 문자열 (EoF 방식, OS별로 처리 방식이 다름)
Stylelint란?
css 정적 분석 도구 중 하나로 최신 css 문법을 지원하며 쉽게 규칙을 추가할 수 있도록 돕는 도구이다.
[VSCode Stylelint 확장 설치]

[Stylelint 패키지 설치]
yarn add -D stylelint stylelint-config-recommended stylelint-config-styled-components
postcss postcss-syntax @stylelint/postcss-css-in-js stylelint-config-clean-orderstylelint
: stylelint의 사용을 가능토록 해 준다
stylelint-config-recommended
: stylelint에서 제공하 오류 방지에 도움이 되는 규칙들
stylelint-config-styled-components
: 스타일 컴포넌트에서 stylelint가 사용될 수 있도록
postcss postcss-syntax @stylelint/postcss-css-in-js
: stylelint 14버전의 호환에 맞게 설치하도록 해준다고 한
stylelint-config-clean-order
: stylelint의 순서에 맞춰 order 설정
[.stylelintrc 설정]
-> extends는 package.json에 나열된 순서대로 작성!
{
"plugins": ["stylelint-order"],
"extends": ["stylelint-config-clean-order", "stylelint-config-recommended", "stylelint-config-styled-components"],
"overrides": [
{
"files": ["**/*.{ts,tsx}"],
"customSyntax": "@stylelint/postcss-css-in-js"
}
}
<rules 설정>
https://stylelint.io/user-guide/rules/#whitespace-inside 참고!
declaration-empty-line-before
: 빈 줄을 허용하지 않음
order/order
: 속성 나열 순서 지정 (custom 먼저)
order/properties-order
: 속성 순서
declaration-property-unit-allowed-list
: 선언 내에서 허용되는 속성 및 단위 쌍 목록을 지정 (border은 px, padding이나 gap은 rem)
unit-allowed-list
: 허용되는 단위 목록을 지정 ( %, deg, px, rem, ms)
color-named
: never로 지정해 색상을 이름이 아닌 #00000 형식으로 작성하게 함
property-no-vendor-prefix
: 속성에 대해 허용하지 없는 접두사
length-zero-no-unit
: 단위가 0인 경우 속성을 허용하지 않음
a { -webkit-transform: scale(1); }
/** ↑
* This prefix */ "rules": {
"declaration-empty-line-before": [
"never",
{
"ignore": ["after-comment", "after-declaration", "inside-single-line-block"]
}
],
"order/order": ["custom-properties", "declarations"],
"order/properties-order": [
{
"groupName": "Positioning",
"noEmptyLineBetween": true,
"properties": ["position", "top", "right", "bottom", "left", "z-index"]
},
{
"groupName": "BoxModel",
"emptyLineBefore": "always",
"noEmptyLineBetween": true,
"properties": [
"display",
"flex",
"flex-basis",
"flex-direction",
"flex-flow",
"flex-grow",
"flex-shrink",
"flex-wrap",
"grid",
"grid-area",
"grid-auto-rows",
"grid-auto-columns",
"grid-auto-flow",
"grid-gap",
"grid-row",
"grid-row-start",
"grid-row-end",
"grid-row-gap",
"grid-column",
"grid-column-start",
"grid-column-end",
"grid-column-gap",
"grid-template",
"grid-template-areas",
"grid-template-rows",
"grid-template-columns",
"gap",
"align-content",
"align-items",
"align-self",
"justify-content",
"justify-items",
"justify-self",
"order",
"float",
"clear",
"box-sizing",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"object-fit",
"object-position",
"overflow",
"overflow-x",
"overflow-y"
]
},
{
"groupName": "Typography",
"emptyLineBefore": "always",
"noEmptyLineBetween": true,
"properties": [
"color",
"font",
"font-weight",
"font-size",
"font-family",
"font-style",
"font-variant",
"font-size-adjust",
"font-stretch",
"font-effect",
"font-emphasize",
"font-emphasize-position",
"font-emphasize-style",
"font-smooth",
"line-height",
"direction",
"letter-spacing",
"white-space",
"text-align",
"text-align-last",
"text-transform",
"text-decoration",
"text-emphasis",
"text-emphasis-color",
"text-emphasis-style",
"text-emphasis-position",
"text-indent",
"text-justify",
"text-outline",
"text-wrap",
"text-overflow",
"text-overflow-ellipsis",
"text-overflow-mode",
"text-orientation",
"text-shadow",
"vertical-align",
"word-wrap",
"word-break",
"word-spacing",
"overflow-wrap",
"tab-size",
"hyphens",
"unicode-bidi",
"columns",
"column-count",
"column-fill",
"column-gap",
"column-rule",
"column-rule-color",
"column-rule-style",
"column-rule-width",
"column-span",
"column-width",
"page-break-after",
"page-break-before",
"page-break-inside",
"src"
]
},
{
"groupName": "Visual",
"emptyLineBefore": "always",
"noEmptyLineBetween": true,
"properties": [
"list-style",
"list-style-position",
"list-style-type",
"list-style-image",
"table-layout",
"empty-cells",
"caption-side",
"background",
"background-color",
"background-image",
"background-repeat",
"background-position",
"background-position-x",
"background-position-y",
"background-size",
"background-clip",
"background-origin",
"background-attachment",
"background-blend-mode",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"box-shadow",
"box-decoration-break",
"transform",
"transform-origin",
"transform-style",
"backface-visibility",
"perspective",
"perspective-origin",
"visibility",
"cursor",
"opacity",
"filter",
"isolation",
"backdrop-filter",
"mix-blend-mode",
"border",
"border-color",
"border-style",
"border-width",
"border-top",
"border-top-color",
"border-top-width",
"border-top-style",
"border-right",
"border-right-color",
"border-right-width",
"border-right-style",
"border-bottom",
"border-bottom-color",
"border-bottom-width",
"border-bottom-style",
"border-left",
"border-left-color",
"border-left-width",
"border-left-style",
"border-radius",
"border-top-left-radius",
"border-top-right-radius",
"border-bottom-right-radius",
"border-bottom-left-radius",
"border-image",
"border-image-source",
"border-image-slice",
"border-image-width",
"border-image-outset",
"border-image-repeat",
"border-collapse",
"border-spacing"
]
},
{
"groupName": "Animation",
"emptyLineBefore": "always",
"noEmptyLineBetween": true,
"properties": [
"transition",
"transition-delay",
"transition-timing-function",
"transition-duration",
"transition-property",
"animation",
"animation-name",
"animation-duration",
"animation-play-state",
"animation-timing-function",
"animation-delay",
"animation-iteration-count",
"animation-direction",
"animation-fill-mode"
]
},
{
"groupName": "Misc",
"emptyLineBefore": "always",
"noEmptyLineBetween": true,
"properties": [
"appearance",
"content",
"clip",
"clip-path",
"counter-reset",
"counter-increment",
"resize",
"user-select",
"nav-index",
"nav-up",
"nav-right",
"nav-down",
"nav-left",
"pointer-events",
"quotes",
"touch-action",
"will-change",
"zoom",
"fill",
"fill-rule",
"clip-rule",
"stroke"
]
}
],
"declaration-property-unit-allowed-list": {
"/^border/": ["px"],
"/^padding|^gap/": ["rem"]
},
"unit-allowed-list": ["%", "deg", "px", "rem", "ms"],
"color-named": "never",
"property-no-vendor-prefix": null
}
}설정하던 중 에러를 마주함...

no-missing-end-of-source-newline 에러가 자꾸 나는 것! ㅜㅜ
스타일드 컴포넌트만 적용하려고 하면 발생하는 에러에 급하게 구글링 시작

Unknow Error은 스타일린트 버전 문제이거나 규칙이 올바르게 작성되지 않아서 발생하는 오류라고 한다. .stylelintrc 내에 no-missing-end-of-source-newline를 작성하지 않았던 터라 오타 문제는 아닐테고... no-missing-end-of-source-newline: null로 추가해 보아도 에러는 그대로였고, 찾아 보니 no-missing-end-of-source-newline는 최신 버전으로 업데이트 되면서 사용되지 않는 규칙으로 확인됐다.
그럼 작성하지도 않은 코드에 대해 왜 에러가 나타나지...?! stylelint-config-styled-components 의 최신 업데이트가 6년 전인데, no-missing-end-of-source-newline는 이보다 최근에 stylelint에서 삭제된 규칙으로 보인다 따라서 두 패키지의 버전 차이로 인한 오류로 판단하고 .stylelintrc에서 stylelint-config-styled-components를 삭제했더니 에러가 말끔히 사라졌다!!
해결 시 참고
https://stackoverflow.com/questions/75346028/unexpected-missing-end-of-source-newline
