Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions .eslintrc.cjs

This file was deleted.

23 changes: 12 additions & 11 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,24 @@

### 심화과제

- 재사용 가능한 Custom UI 컴포넌트를 만들어 보기
- 재사용 가능한 Custom 라이브러리 Hook을 만들어 보기
- 재사용 가능한 Custom 유틸 함수를 만들어 보기
- 그래서 엔티티와는 어떤 다른 계층적 특징을 가지는지 이해하기
- 이번 심화과제는 Context나 Jotai를 사용해서 Props drilling을 없애는 것입니다.
- 어떤 props는 남겨야 하는지, 어떤 props는 제거해야 하는지에 대한 기준을 세워보세요.
- Context나 Jotai를 사용하여 상태를 관리하는 방법을 익히고, 이를 통해 컴포넌트 간의 데이터 전달을 효율적으로 처리할 수 있습니다.

- [ ] Context나 Jotai를 사용해서 전역상태관리를 구축했나요?
- [ ] 전역상태관리를 통해 domain custom hook을 적절하게 리팩토링 했나요?
- [ ] 도메인 컴포넌트에 도메인 props는 남기고 props drilling을 유발하는 불필요한 props는 잘 제거했나요?
- [ ] 전체적으로 분리와 재조립이 더 수월해진 결합도가 낮아진 코드가 되었나요?

- [ ] UI 컴포넌트 계층과 엔티티 컴포넌트의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
- [ ] 엔티티 Hook과 라이브러리 훅과의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
- [ ] 엔티티 순수함수와 유틸리티 함수의 계층의 성격이 다르다는 것을 이해하고 적용했는가?

## 과제 셀프회고

<!-- 과제에 대한 회고를 작성해주세요 -->

### 과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?
### 과제를 하면서 내가 알게된 점, 좋았던 점은 무엇인가요?

### 과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?
### 이번 과제에서 내가 제일 신경 쓴 부분은 무엇인가요?

### 리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
### 이번 과제를 통해 앞으로 해보고 싶은게 있다면 알려주세요!

## 리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문
### 리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
21 changes: 17 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

name: CI

on:
Expand All @@ -20,21 +21,33 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20

- uses: pnpm/action-setup@v2
with:
version: latest

- name: test basic
run: |
npm install
npm run test:basic
pnpm install
pnpm run test:basic

advacned:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/setup-node@v4
with:
node-version: 20

- uses: pnpm/action-setup@v2
with:
version: latest

- name: advanced-test
run: |
npm install
npm run test:advanced
pnpm install
pnpm run test:advanced
59 changes: 59 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Deploy to GitHub Pages

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build-and-deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'

- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8

- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --no-frozen-lockfile

- name: Build
run: pnpm run build

- name: Copy HTML files with friendly names
run: |
if [ -f "dist/index.basic.html" ]; then
cp dist/index.basic.html dist/basic.html
echo "✅ basic.html 복사 완료"
fi
if [ -f "dist/index.advanced.html" ]; then
cp dist/index.advanced.html dist/advanced.html
echo "✅ advanced.html 복사 완료"
fi
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"tabWidth": 2,
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"printWidth": 100,
"endOfLine": "auto"
}
130 changes: 130 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import typescript from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
import { defineConfig } from 'eslint/config';
import prettier from 'eslint-config-prettier';
import compat from 'eslint-plugin-compat';
import importPlugin from 'eslint-plugin-import';
import eslintPluginPrettier from 'eslint-plugin-prettier';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';

export default defineConfig([
{
ignores: ['**/node_modules/**', 'dist/**', '.eslintrc.cjs'],
},
{
files: ['**/*.{js,jsx,ts,tsx}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parser: typescriptParser,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
tsconfigRootDir: '.',
},
},
plugins: {
prettier: eslintPluginPrettier,
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
'@typescript-eslint': typescript,
compat,
import: importPlugin,
},
settings: {
react: {
version: 'detect',
},
browsers: '> 0.5%, last 2 versions, not op_mini all, Firefox ESR, not dead',
},
rules: {
// 기존 규칙 유지
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],

// Prettier 통합 규칙
'comma-dangle': [
'error',
{
arrays: 'always-multiline',
objects: 'always-multiline',
imports: 'always-multiline',
exports: 'always-multiline',
functions: 'never',
},
],

// React 관련 규칙
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
'react-hooks/rules-of-hooks': 'error',

// TypeScript 관련 규칙
'@typescript-eslint/no-explicit-any': 'warn',

// 팀 컨벤션 - var 사용 금지
'no-var': 'error',
'@typescript-eslint/no-unused-vars': 'error',

// 팀 컨벤션 - 동등 연산자 (==, !=) 금지
eqeqeq: ['error', 'always', { null: 'ignore' }],

// 팀 컨벤션 - 얼리 리턴 권장
'consistent-return': 'error',
'no-else-return': ['error', { allowElseIf: false }],

// 팀 컨벤션 - 템플릿 리터럴 규칙
'prefer-template': 'error',

// 팀 컨벤션 - 상수는 대문자
camelcase: [
'error',
{
properties: 'never',
ignoreDestructuring: false,
ignoreImports: false,
ignoreGlobals: false,
allow: ['^[A-Z][A-Z0-9_]*$'],
},
],

// 팀 컨벤션 - 구조분해할당 권장
'prefer-destructuring': [
'error',
{
array: true,
object: true,
},
{
enforceForRenamedProperties: false,
},
],

// 기본 코드 품질 규칙
'prefer-const': 'error',
'object-shorthand': 'error',
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-debugger': 'warn',
'no-undef': 'off',

// import 순서 규칙
'import/order': [
'error',
{
groups: ['builtin', 'external', ['parent', 'sibling'], 'index'],
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
'newlines-between': 'always',
},
],
'import/extensions': 'off',
},
},
prettier,
]);
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
"jotai": "^2.13.0",
"react": "^19.1.1",
"react-dom": "^19.1.1"
},
Expand All @@ -30,6 +31,11 @@
"@vitejs/plugin-react-swc": "^3.11.0",
"@vitest/ui": "^3.2.4",
"eslint": "^9.32.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-compat": "^6.0.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.3",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"jsdom": "^26.1.0",
Expand Down
Loading