Hello Kitty Eyes Shut
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ’ป๊ณต๋ถ€ ๊ธฐ๋ก/๐Ÿ“Œ Frontend

[Frontend] ESLint v9๋กœ TS+React ๋ฆฐํŒ… ํ™˜๊ฒฝ ๋งŒ๋“ค๊ธฐ

๋ฐ˜์‘ํ˜•

 

 

 

 

๐Ÿ“‘ ๋“ค์–ด๊ฐ€๋ฉฐ

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ ESLint v9 ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์‚ดํŽด๋ดค์œผ๋‹ˆ,

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ๋‚ด๊ฐ€ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์ ์šฉํ•˜๋ ค๊ณ  ์„ค์ •ํ•œ eslint.config.js๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ

์™œ ์ด๋ ‡๊ฒŒ ์„ค์ •์„ ํ–ˆ๋Š”์ง€, ๊ฐ ์˜ต์…˜์ด ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€๋ฅผ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•œ๋‹ค.

 

 

[Frontend] ESLint v9 ๊ณต์‹ ๋ฌธ์„œ ๋œฏ์–ด๋ณด๊ธฐ

๋ชฉ์ฐจ (OPEN)๐Ÿ“‘ ๋“ค์–ด๊ฐ€๋ฉฐ๐ŸŸฅ typescript-eslint๋ž€๐ŸŸง defineConfig( )์™€ tseslint.config( )์˜ ๊ด€๊ณ„๐ŸŸจ Flat Config์˜ ๋“ฑ์žฅ๊ณผ ๋ณ€ํ™”์˜ ๋ฐฐ๊ฒฝ๐ŸŸฉ Vite ํ…œํ”Œ๋ฆฟ์ด ๋งŒ๋“ค์–ด์ค€ ๊ธฐ๋ณธ ESLint ์„ค์ • ๋œฏ์–ด๋ณด๊ธฐ๐ŸŸฆ ์ฒ˜์Œ ๋˜์กŒ๋˜ ๋‹ค์„ฏ ๊ฐ€

sso-codingdiary.tistory.com

 

 


๐ŸŸฅ ํ™˜๊ฒฝ

  • ์Šคํƒ: Vite + React + TypeScript
  • ESLint: v9 (Flat Config ๊ธฐ๋ฐ˜)

 

 


๐ŸŸง ์ตœ์ข… ์„ค์ • ํŒŒ์ผ

import js from '@eslint/js'
import globals from 'globals'
import tseslint from 'typescript-eslint'
import reactPlugin from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'

export default defineConfig([
  // 1) ๋ฆฐํŒ… ๋ฒ”์œ„ ์ตœ์†Œํ™”
  globalIgnores(['dist', 'node_modules']),

  // 2) React + TS ํŒŒ์ผ์—๋งŒ ๋ฃฐ ์ ์šฉ
  {
    files: ['**/*.{ts,tsx}'],
    // d.ts๋Š” ํƒ€์ž… ์„ ์–ธ ํŒŒ์ผ์ด๋ผ ๊ทœ์น™ ์ ์šฉ ๋Œ€์ƒ์—์„œ ์ œ์™ธ
    ignores: ['**/*.d.ts'],

    // 3) ์ถ”์ฒœ ๊ทœ์น™ ์„ธํŠธ ํ™•์žฅ
    extends: [
      js.configs.recommended,
      ...tseslint.configs.recommended,          // TS ์ถ”์ฒœ ๋ฃฐ(๋ฐฐ์—ด์ด๋ผ ์ „๊ฐœ)
      reactPlugin.configs.flat.recommended,     // React ๊ธฐ๋ณธ ๊ถŒ์žฅ
      reactHooks.configs['recommended-latest'], // Hooks ๊ทœ์น™
      reactRefresh.configs.vite,                // Vite + Fast Refresh ์ œ์•ฝ
    ],

    // 4) ์ฝ”๋“œ ์ดํ•ด ๋Šฅ๋ ฅ ์ƒํ–ฅ (TS ๋ฌธ๋ฒ•/ํƒ€์ž… ์ธ์ง€)
    languageOptions: {
      ecmaVersion: 2020,
      sourceType: 'module',        // import/export ๊ตฌ๋ฌธ ์ธ์‹
      parser: tseslint.parser,     // TS ๋ฌธ๋ฒ• ํŒŒ์‹ฑ
      parserOptions: { projectService: true },  // TSConfig ๊ธฐ๋ฐ˜์˜ ํƒ€์ž… ์ธ์ง€ ๋ฃฐ ON
      globals: { ...globals.browser },          // window, document ๋“ฑ ์ „์—ญ ์‹๋ณ„์ž ์ธ์‹
    },

    // 5) React ๋ฒ„์ „ ์ธ์ง€ (๋ฃฐ ๋™์ž‘์ด ๋ฒ„์ „์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง)
    settings: {
      react: { version: 'detect' },
    },

    // 6) ์ปค์Šคํ…€ ๋ฃฐ
    rules: {
      // ์šด์˜ ๋ฐฐํฌ ์‹œ ๋‚จ๊ธฐ๊ณ  ์‹ถ์€ ์ฝ˜์†”๋งŒ ํ—ˆ์šฉ
      'no-console': ['warn', { allow: ['warn', 'error'] }],
      'no-debugger': 'error',
      
      // React 17+ ๋ถ€ํ„ฐ๋Š” import React ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ๋น„ํ™œ์„ฑํ™”
      'react/react-in-jsx-scope': 'off',

      // TS๋กœ PropTypes ๋Œ€์ฒด
      'react/prop-types': 'off',

      // ๋ฏธ์‚ฌ์šฉ ๋ณ€์ˆ˜ ์žก๋˜, ์˜๋„์  ๋ฏธ์‚ฌ์šฉ(_prefix)์€ ํ—ˆ์šฉ
      '@typescript-eslint/no-unused-vars': [
        'warn',
        { argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
      ],
      // any ๋‚จ๋ฐœ ๋ฐฉ์ง€ (ํŒ€ ์ƒํ™ฉ ๋”ฐ๋ผ 'error'๋กœ ๊ฒฉ์ƒ ๊ฐ€๋Šฅ)
      '@typescript-eslint/no-explicit-any': 'warn',
    },
  },
])

 

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด, ์œ„์™€ ๊ฐ™์ด ์„ค์ •ํ•จ์œผ๋กœ์จ

๊ฒ€์‚ฌ ๋ฒ”์œ„๋ฅผ ์ค„์—ฌ์„œ ์†๋„๋ฅผ ํ™•๋ณดํ•˜๊ณ , ESLint๊ฐ€ TS ํƒ€์ž… ์ •๋ณด๊นŒ์ง€ ์ธ์ง€ํ•ด์„œ ๊ทœ์น™์„ ๋” ์ •ํ™•ํžˆ ์ ์šฉํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

 

 


๐ŸŸจ ์„ค์ • ์„ค๋ช…

1. globalIgnores(['dist', 'node_modules'])

ESLint๊ฐ€ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š์•„๋„ ๋˜๋Š” ํด๋”๋ฅผ ์ง€์ •ํ•ด์ค€๋‹ค.

๋ณดํ†ต ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฌผ(dist)๊ณผ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(node_modules)๋Š” ์ž๋™ ์ƒ์„ฑ๋œ ์ฝ”๋“œ์ด๋ฏ€๋กœ

๋ฆฐํŠธํ•  ํ•„์š”๊ฐ€ ์—†์–ด์„œ ์ œ์™ธํ•ด์ฃผ์—ˆ๋‹ค.

 

 

2. extends

์–ด๋–ค ๊ทœ์น™ ์„ธํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฒ€์‚ฌํ• ์ง€๋ฅผ ์ •ํ•ด์ฃผ๋Š” ๊ฒƒ์œผ๋กœ,

๋‚ด ์„ค์ •์— ์‚ฌ์šฉ๋œ ๊ฐ๊ฐ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

์„ค์ • ์„ค๋ช…
js.configs.recommended ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ธฐ๋ณธ ๊ถŒ์žฅ ๊ทœ์น™
tseslint.configs.recommended ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๋ฌธ๋ฒ• + ํƒ€์ž… ๊ธฐ๋ฐ˜ ๊ทœ์น™
reactPlugin.configs.flat.recommended React ์ „์šฉ ๊ทœ์น™
reactHooks.configs['recommended-latest'] useEffect, useState ๊ฐ™์€ ํ›… ๊ด€๋ จ ๊ทœ์น™
reactRefresh.configs.vite Vite์˜ Fast Refresh ์•ˆ์ •์„ฑ ์ฒดํฌ์šฉ

 

 

3. languageOptions

ESLint๊ฐ€ ์ฝ”๋“œ๋ฅผ ์–ด๋–ค ๋ฌธ๋ฒ•๊ณผ ํ™˜๊ฒฝ์œผ๋กœ ์ดํ•ดํ• ์ง€๋ฅผ ์„ค์ •ํ•ด์ค€๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด์คŒ์œผ๋กœ์จ, ESLint๊ฐ€ 'TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ ํ”„๋กœ์ ํŠธ'์ž„์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์—ˆ๋‹ค.

ํ‚ค ์—ญํ• 
ecmaVersion: 2020 ์ตœ์‹  JS ๋ฌธ๋ฒ• ์ง€์›
sourceType: 'module' import/export ๊ตฌ๋ฌธ ์‚ฌ์šฉ ํ—ˆ์šฉ
parser: tseslint.parser TS ๋ฌธ๋ฒ• ํ•ด์„ (๊ธฐ๋ณธ ESLint๋Š” TS ๋ชจ๋ฆ„)
parserOptions.projectService: true TS ํƒ€์ž… ์ •๋ณด ๊ธฐ๋ฐ˜ ๊ทœ์น™ ํ™œ์„ฑํ™”
globals.browser window, document ๋“ฑ ๋ธŒ๋ผ์šฐ์ € ์ „์—ญ ์‹๋ณ„์ž ์ธ์‹

 

 

4. settings.react.version: 'detect'

React ๊ด€๋ จ ๊ทœ์น™๋“ค์€ ๋ฒ„์ „์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์—

๋ฒ„์ „์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด, React 17 ์ดํ›„๋ถ€ํ„ฐ๋Š” JSX๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ import React from 'react'๊ฐ€ ํ•„์š” ์—†๊ธฐ ๋•Œ๋ฌธ์—
์ด ์˜ต์…˜์ด ์—†์œผ๋ฉด ๋ถˆํ•„์š”ํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

 

 

5. rules

ํŒ€์—์„œ ์ž์ฃผ ๊ฒช๋Š” ํŒจํ„ด์„ ์ง์ ‘ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์œผ๋กœ, ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•œ ๊ทœ์น™์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

๊ทœ์น™ ์˜๋ฏธ
no-console ๊ฐœ๋ฐœ์šฉ ๋กœ๊ทธ๋Š” ํ—ˆ์šฉ, ๋ฐฐํฌ์šฉ์€ ๊ฒฝ๊ณ 
no-debugger ๋ฐฐํฌ ์ฝ”๋“œ์—์„œ ๋””๋ฒ„๊ฑฐ ๊ธˆ์ง€
react/react-in-jsx-scope React 17 ์ด์ƒ์—์„œ๋Š” JSX ์‚ฌ์šฉ ์‹œ
import React๊ฐ€ ํ•„์š” ์—†์œผ๋ฏ€๋กœ ๋น„ํ™œ์„ฑํ™”
react/prop-types TypeScript ํ™˜๊ฒฝ์—์„œ๋Š” PropTypes ๋Œ€์‹  TS ํƒ€์ž… ์‚ฌ์šฉ
@typescript-eslint/no-unused-vars ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ณ€์ˆ˜ ์žก๊ธฐ (๋‹จ, _๋กœ ์‹œ์ž‘ํ•˜๋ฉด ๋ฌด์‹œ)
@typescript-eslint/no-explicit-any any ํƒ€์ž… ์‚ฌ์šฉ ์‹œ ๊ฒฝ๊ณ  (์ ์ง„์  ๊ฐœ์„ ์šฉ)

 

 


๐Ÿ“š ๊ฒฐ๋ก 

๋‚ด ์„ค์ •์˜ ํ•ต์‹ฌ์€ ์ •ํ™•ํ•œ ๊ฒ€์‚ฌ + ๋น ๋ฅธ ์†๋„ + ํ˜„์‹ค์ ์ธ ๊ทœ์น™์ด์—ˆ๋‹ค.

 

globalIgnores๋กœ ๊ฒ€์‚ฌ ๋ฒ”์œ„๋ฅผ ์ค„์ด๊ณ ,

typescript-eslint๋กœ ํƒ€์ž… ๊ธฐ๋ฐ˜ ๊ทœ์น™์„ ํ™œ์„ฑํ™” ํ•˜๋ฉฐ,

extends๋กœ React / TS ์ „์šฉ ๊ทœ์น™์„ ํ•œ ๋ฒˆ์— ๋ง์”Œ์›Œ์ฃผ์—ˆ๋‹ค.

 

ํ™•์‹คํžˆ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ํ•œ ๋ฒˆ ๊ผผ๊ผผํžˆ ๋ณธ ํ›„์— ์ง์ ‘ ์„ค์ •์„ ์ž‘์„ฑํ•˜๋‹ˆ๊นŒ

๊ทธ๋™์•ˆ ๋‚จ๋“ค์ด ์ž‘์„ฑํ•ด๋‘” ์„ค์ •์„ ๊ฐ€์ ธ์™€์„œ ์“ฐ๋ฉด์„œ

'๊ฐ‘์ž๊ธฐ ์—ฌ๊ธฐ์„œ๋Š” ์—๋Ÿฌ๊ฐ€ ์™œ ๋‚˜๋Š” ๊ฑฐ์ง€ ..' ํ•˜๋Š” ์ƒํ™ฉ์ด ์ค„์–ด๋“ค ๊ฒƒ ๊ฐ™๋‹ค.

๋ฐ˜์‘ํ˜•