diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index b50656a..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": [ - "next/core-web-vitals", // Next.js 기본 규칙 - "prettier" // Prettier와 충돌하지 않도록 조정 - ], - "plugins": ["prettier"], - "rules": { - "prettier/prettier": "error", // Prettier를 ESLint 오류로 간주 - "react/react-in-jsx-scope": "off", // React 17+에서 불필요 - "import/prefer-default-export": "off", // 필요 시 규칙 비활성화 (옵션) - "react/jsx-props-no-spreading": "off" // Props 스프레드 허용 (옵션) - }, - "settings": { - "react": { - "version": "detect" // 프로젝트의 React 버전 자동 감지 - } - } -} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6150ffd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", // Prettier를 기본 포맷터로 설정 + "editor.formatOnSave": true, // 저장 시 자동으로 포맷팅 + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } +} diff --git a/components/DarkmodeToggle.tsx b/components/DarkmodeToggle.tsx index c8611ef..06e8cf9 100644 --- a/components/DarkmodeToggle.tsx +++ b/components/DarkmodeToggle.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useEffect, useState } from 'react'; export default function DarkModeToggle() { const [isDarkMode, setIsDarkMode] = useState(false); @@ -14,12 +14,12 @@ export default function DarkModeToggle() { return ( diff --git a/eslint.config.cjs b/eslint.config.cjs new file mode 100644 index 0000000..06b6d39 --- /dev/null +++ b/eslint.config.cjs @@ -0,0 +1,87 @@ +// eslint.config.cjs +const prettierPlugin = require('eslint-plugin-prettier'); +const reactPlugin = require('eslint-plugin-react'); +const tsPlugin = require('@typescript-eslint/eslint-plugin'); +const tsParser = require('@typescript-eslint/parser'); +const importPlugin = require('eslint-plugin-import'); +const simpleImportSortPlugin = require('eslint-plugin-simple-import-sort'); + +module.exports = [ + { + // 검사할 파일 패턴 + files: ['pages/**/*.{js,jsx,ts,tsx}', 'components/**/*.{js,jsx,ts,tsx}'], // 검사 대상 파일 + ignores: ['node_modules', '.next', 'dist'], // 검사에서 제외할 파일 및 폴더 + languageOptions: { + ecmaVersion: 'latest', // 최신 ECMAScript 문법 허용 + sourceType: 'module', // ECMAScript 모듈 사용 + parser: tsParser, // TypeScript 파일을 파싱할 파서 설정 + parserOptions: { + ecmaFeatures: { jsx: true }, // JSX 문법 허용 + project: null, // TypeScript 프로젝트 설정 (타입 기반 분석 미사용) + }, + }, + plugins: { + prettier: prettierPlugin, // Prettier와 ESLint 연동 + react: reactPlugin, // React 관련 규칙 활성화 + '@typescript-eslint': tsPlugin, // TypeScript 관련 규칙 활성화 + import: importPlugin, // Import 관련 규칙 활성화 + 'simple-import-sort': simpleImportSortPlugin, // Import 정렬 관련 규칙 활성화 + }, + rules: { + // Prettier 관련 규칙 + 'prettier/prettier': 'error', // Prettier에서 감지한 스타일 위반을 ESLint 에러로 처리 + + // React 관련 규칙 + 'react/react-in-jsx-scope': 'off', // React 17+에서는 import React가 필요 없으므로 비활성화 + + // TypeScript 관련 규칙 + '@typescript-eslint/no-unused-vars': ['error'], // 사용되지 않는 변수에 대해 에러 표시 + '@typescript-eslint/explicit-module-boundary-types': 'off', // 함수 반환 타입 명시를 강제하지 않음 + + // Import/Export 관련 규칙 + 'import/newline-after-import': 'error', // import 문 다음에 빈 줄 강제 + 'simple-import-sort/imports': [ + 'error', + { + groups: [ + // Node.js built-ins + ['^node:'], + // Packages + ['^@?\\w'], + // Absolute imports and other imports such as Vue-style `@/foo` + ['^@/'], + // Relative imports + ['^\\.'], + // Style imports + ['^.+\\.s?css$'], + ], + }, + ], + 'simple-import-sort/exports': 'error', + }, + settings: { + react: { + version: 'detect', // React 버전을 자동으로 감지 (설정 불필요) + }, + 'import/resolver': { + node: { + paths: ['.'], + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + alias: { + map: [ + ['@/components', './components'], + ['@/styles', './styles'], + ['@/pages', './pages'], + ['@/utils', './utils'], + ['@/hooks', './hooks'], + ], + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + }, + }, + }, + { + ignores: ['.next'], // .next 폴더를 전역적으로 무시 + }, +]; diff --git a/package-lock.json b/package-lock.json index 94a4a9e..765a356 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "wikid", "version": "0.1.0", "dependencies": { + "@next/eslint-plugin-next": "^15.1.0", "@tanstack/react-query": "^5.62.7", "axios": "^1.7.9", "next": "^15.1.0", @@ -16,17 +17,21 @@ "react-dom": "^19.0.0" }, "devDependencies": { - "@eslint/eslintrc": "^3", - "@eslint/js": "^9.16.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^8.57.1", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@typescript-eslint/eslint-plugin": "^8.18.0", + "@typescript-eslint/parser": "^8.18.0", "autoprefixer": "^10.4.20", "eslint": "^9.16.0", "eslint-config-next": "^15.1.0", "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.2", + "eslint-plugin-simple-import-sort": "^12.1.1", "globals": "^15.13.0", "postcss": "^8.4.49", "prettier": "^3.4.2", @@ -167,13 +172,13 @@ } }, "node_modules/@eslint/js": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", - "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@eslint/object-schema": { @@ -707,7 +712,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.1.0.tgz", "integrity": "sha512-+jPT0h+nelBT6HC9ZCHGc7DgGVy04cv4shYdAe6tKlEbjQUtwU3LzQhzbDHQyY2m6g39m6B0kOFVuLGBrxxbGg==", - "dev": true, "license": "MIT", "dependencies": { "fast-glob": "3.3.1" @@ -845,7 +849,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -859,7 +862,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -869,7 +871,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -1660,7 +1661,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -2783,6 +2783,16 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", + "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, "node_modules/eslint-scope": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", @@ -2813,6 +2823,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/espree": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", @@ -2895,7 +2915,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2912,7 +2931,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -2939,7 +2957,6 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -2962,7 +2979,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -3615,7 +3631,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3667,7 +3682,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -3706,7 +3720,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -4119,7 +4132,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -4129,7 +4141,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -4599,7 +4610,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -5021,7 +5031,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -5173,7 +5182,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -5184,7 +5192,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -5913,7 +5920,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" diff --git a/package.json b/package.json index 569b90b..0019e92 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "test": "npm run lint" }, "dependencies": { + "@next/eslint-plugin-next": "^15.1.0", "@tanstack/react-query": "^5.62.7", "axios": "^1.7.9", "next": "^15.1.0", @@ -18,17 +19,21 @@ "react-dom": "^19.0.0" }, "devDependencies": { - "@eslint/eslintrc": "^3", - "@eslint/js": "^9.16.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^8.57.1", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@typescript-eslint/eslint-plugin": "^8.18.0", + "@typescript-eslint/parser": "^8.18.0", "autoprefixer": "^10.4.20", "eslint": "^9.16.0", "eslint-config-next": "^15.1.0", "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.2", + "eslint-plugin-simple-import-sort": "^12.1.1", "globals": "^15.13.0", "postcss": "^8.4.49", "prettier": "^3.4.2", diff --git a/pages/_app.tsx b/pages/_app.tsx index 9568b93..6fa9382 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,7 +1,9 @@ -import '@/styles/globals.css'; import type { AppProps } from 'next/app'; + import DarkModeToggle from '@/components/DarkmodeToggle'; +import '@/styles/globals.css'; + export default function App({ Component, pageProps }: AppProps) { return ( <> diff --git a/pages/_document.tsx b/pages/_document.tsx index 22fa775..b612fb1 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -1,12 +1,12 @@ -import { Html, Head, Main, NextScript } from 'next/document'; +import { Head, Html, Main, NextScript } from 'next/document'; export default function Document() { return (