Skip to content

Feat: SOSO UI 패키지 설정 및 버튼 추가#93

Merged
DreamPaste merged 14 commits intodevfrom
feat/SOS-47-package-ui-init
Dec 23, 2025
Merged

Feat: SOSO UI 패키지 설정 및 버튼 추가#93
DreamPaste merged 14 commits intodevfrom
feat/SOS-47-package-ui-init

Conversation

@DreamPaste
Copy link
Member

📌 개요

UI 패키지 기본 설정 및 빌드 시스템 구축

  • @soso/ui 패키지 설정 (exports, peerDependencies)
  • tsup 빌드 시스템 구축 (ESM/CJS/DTS)
  • Vitest 단위 테스트 환경 구축
  • npm 배포 준비 (.npmignore, README.md)
  • Button 컴포넌트 예제 작성 및 테스트 코트 작성

🗒 상세 설명

1. @soso/ui 패키지 설정

프로덕션급 React 컴포넌트 라이브러리를 위한 package.json을 구성했습니다.

핵심 기술 및 구현사항

  • Modern Package Exports: ESM/CJS 동시 지원

    • exports 필드로 조건부 export 설정
    • TypeScript 타입 선언 파일 (.d.ts, .d.mts) 자동 제공
    • Tree-shaking 최적화
  • Peer Dependencies 관리:

    • React ^18.2.0 지정 (메인 앱과 동일한 버전)
    • react-dom ^18.2.0 지정
  • npm 배포 설정:

    • publishConfig.access: "public" - 공개 패키지
    • files 필드로 배포 파일 제한 (dist, README, CHANGELOG만)

사용 예시

# 다른 패키지에서 사용
pnpm add @soso/ui

# 또는 모노레포 내에서
{
  "dependencies": {
    "@soso/ui": "workspace:*"
  }
}
// ESM import
import { Button } from '@soso/ui';

// 개별 컴포넌트 import (tree-shaking)
import { Button } from '@soso/ui/components/Button';

2. tsup 빌드 시스템 구축

esbuild 기반의 초고속 번들러 tsup을 활용한 빌드 시스템을 구축했습니다.

핵심 기술 및 구현사항

  • Multi-Format 빌드:

    • ESM (dist/index.mjs) - 최신 빌드 도구용
    • CJS (dist/index.js) - 레거시 환경 지원
    • DTS (dist/index.d.ts, dist/index.d.mts) - TypeScript 타입 선언
  • 최적화 기능:

    • Code splitting - 동적 import 지원
    • Tree-shaking - 사용하지 않는 코드 제거
    • Source maps - 디버깅 지원
    • External dependencies - react, react-dom 번들 제외
  • 빌드 속도:

    • esbuild 기반으로 기존 webpack 대비 10-100배 빠름
    • 약 500ms 이내 빌드 완료

빌드 산출물

dist/
├── index.js         # CJS 번들
├── index.js.map     # CJS 소스맵
├── index.d.ts       # CJS 타입 선언
├── index.cjs        # CJS 별칭
├── index.cjs.map
├── index.d.cts      # CJS 타입 별칭
├── index.mjs        # ESM 번들
├── index.mjs.map    # ESM 소스맵
└── index.d.mts      # ESM 타입 선언

사용 예시

# 빌드
pnpm build

# 개발 모드 (watch)
pnpm dev

# 빌드 결과 확인
ls -lh dist/

3. Vitest 단위 테스트 환경 구축

Vite 기반의 초고속 테스트 프레임워크 Vitest를 도입했습니다.

핵심 기술 및 구현사항

  • Testing Library 통합:

    • @testing-library/react - React 컴포넌트 테스트
    • @testing-library/user-event - 사용자 상호작용 시뮬레이션
    • @testing-library/jest-dom - 추가 매처 (toBeInTheDocument, toHaveClass 등)
  • jsdom 환경:

    • 브라우저 API 시뮬레이션
    • DOM 테스트 가능
  • Coverage 설정:

    • v8 provider 사용
    • 80% 커버리지 목표
    • HTML/JSON 리포트 생성
  • Global Test APIs:

    • describe, it, expect 전역으로 사용 가능
    • import 없이 바로 사용

사용 예시

# 테스트 실행
pnpm test

# Watch 모드
pnpm test:watch

# Coverage 리포트 생성
pnpm test:coverage

# UI 모드
pnpm test:ui

4. Button 컴포넌트 추가

SOSO web의 실제 Button 컴포넌트를 packages/ui로 마이그레이션했습니다.
테스트를 위해 기존 apps/web에도 존재합니다.

마이그레이션된 파일

packages/ui/src/
├── components/
│   ├── Button/
│   │   ├── Button.tsx         # 메인 컴포넌트
│   │   ├── Button.test.tsx    # 19개 테스트
│   │   └── index.ts
│   └── Pressable/
│       ├── Pressable.tsx      # 애니메이션 래퍼
│       └── index.ts
├── hooks/
│   ├── useTap.ts              # Pointer 이벤트 핸들링
│   └── useLoadingDelay.ts     # 로딩 지연 처리
├── utils/
│   └── cn.ts                  # Tailwind className 병합
└── constants/
    └── animation.ts           # 애니메이션 토큰

5. 테스트 전략 및 구현

📊 테스트 전략: Vitest vs Storybook 역할 분담

프로덕션급 컴포넌트 테스트를 위해 각 도구의 강점에 맞는 역할을 명확히 분리했습니다.

도구 비중 역할 테스트 항목
Vitest 70% Unit + Integration 로직, 이벤트, 접근성, props 검증
Storybook 25% Visual + Interaction 시각적 상태, 애니메이션, 문서화
Playwright 5% E2E (선택적) 실제 플로우, API 통합

✅ Vitest 테스트 (19개) - 로직 검증

현재 구현 완료

총 19개의 단위 테스트로 Button의 모든 로직을 검증했습니다.

테스트 항목:

  1. 기본 렌더링 (4개)

    • children 렌더링
    • 기본 type="button"
    • type 오버라이드
    • ref 전달
  2. 인터랙션 (2개)

    • onClick 이벤트 처리
    • disabled 시 onClick 차단
  3. Props 검증 (4개)

    • variant 기본값 (filled)
    • variant 변경 시 클래스 적용
    • size 기본값 (md)
    • size 변경 시 클래스 적용
  4. 상태 (5개)

    • disabled 속성
    • disabled 스타일
    • loading 시 aria-busy
    • loading 시 pointer-events-none
    • loading 시 이벤트 바인딩 안 됨
  5. 스타일 (1개)

    • 커스텀 className 병합
  6. 접근성 (3개)

    • button role
    • 포커스 가능
    • disabled 시 포커스 불가

제외한 테스트 (Storybook으로 이관):

  • ❌ 개별 variant 시각적 확인 → Storybook
  • ❌ 개별 size 시각적 확인 → Storybook
  • ❌ 로딩 애니메이션 시각적 확인 → Storybook
  • ❌ Pressable 애니메이션 → Storybook
  • ❌ hover/active/focus 상태 → Storybook

스크린샷

실제 push시 CI로 테스트 코드가 검증되는 모습

image

🔗 이슈

closes #89

SOS-47: UI 패키지 기본 설정 및 빌드 시스템 구축

✅ 체크리스트

  • 코드가 스타일 가이드를 따릅니다
  • 자체 코드 리뷰를 완료했습니다
  • 복잡/핵심 로직에 주석을 추가했습니다
  • 관심사 분리를 확인했습니다 (build, test, component)
  • 잠재적 사이드이펙트를 점검했습니다 (TypeScript incremental 충돌 해결)
  • 모든 테스트가 통과합니다
  • 빌드가 성공적으로 완료됩니다
  • TypeScript 타입 체크가 통과합니다

🧪 테스트 방법

변경 사항을 다음 방법으로 검증했습니다:

1. 의존성 설치

pnpm install

2. 빌드 검증

cd packages/ui
pnpm build

3. 빌드 산출물 확인

ls -lah dist/

4. 테스트 실행

cd packages/ui
pnpm test

5. TypeScript 타입 체크

pnpm typecheck

6. 패키지 exports 확인

node -e "console.log(require('./packages/ui/package.json').exports)"

기술적 결정 사항

1. tsup 선택 이유

  • 빠른 빌드: esbuild 기반, webpack 대비 10-100배 빠름
  • 간단한 설정: Zero-config에 가까운 사용성
  • Multi-format: ESM/CJS/DTS 동시 지원
  • Turborepo 호환: Vercel 공식 추천

2. Vitest 선택 이유

  • Vite 기반: HMR 지원, 빠른 테스트 실행
  • Jest 호환: Jest API와 호환, 마이그레이션 쉬움
  • ESM 네이티브: ESM 모듈 테스트 지원
  • Monorepo 친화적: Workspace 지원

3. exports 필드 설계

  • 조건부 export: import/require 자동 감지
  • TypeScript 타입 우선: types 필드 먼저 제공
  • Subpath exports: 개별 컴포넌트 import 지원

후속 작업

이어서 진행할 작업 계획:

Issue 1.3: Storybook 개발 환경 구축 (예정)

  • apps/storybook/ Storybook 8 앱 생성
  • Vite + Storybook 설정
  • SOSO web 환경과 동일하게 설정 (Tailwind CSS, 폰트, 테마)
  • Addons 설정
    • Controls - prop 조작
    • Actions - 이벤트 로깅
    • A11y - 접근성 검증
    • Interactions - 상호작용 테스트
  • @soso/ui 통합
  • Button 컴포넌트 스토리 작성
  • Interaction tests (Play functions)
  • Playwright 연동 (E2E)

@DreamPaste DreamPaste requested a review from youdaeng2 December 6, 2025 11:41
@DreamPaste DreamPaste self-assigned this Dec 6, 2025
Copilot AI review requested due to automatic review settings December 6, 2025 11:41
@DreamPaste DreamPaste added Feat 💡 새로운 기능을 구현하고 추가합니다! 휘건 labels Dec 6, 2025
@linear
Copy link

linear bot commented Dec 6, 2025

@github-actions
Copy link

github-actions bot commented Dec 6, 2025

📦 번들 분석 결과

📊 번들 크기 요약

항목
📦 전체 번들 크기 3.7M
📄 JavaScript 크기 1.6M
🗂️ JavaScript 파일 수 64개

🔍 주요 청크 파일 (크기순)

79e27356-a397cfaca953c890.js - 169K
framework-69e0f7d37422957b.js - 137K
main-a3247b30c12eafe6.js - 130K
2356-dea7484209cf7469.js - 122K
9870-dbaf3a370645f2d3.js - 121K
polyfills-42372ed130431b0a.js - 110K
5867-b97ee42a40c66b62.js - 90K
5251-dc07ab16b26ff9a9.js - 75K
page-a1946fe19c26d153.js - 30K
2845-56a40d00b08c6d2e.js - 28K

🤖 자동 생성된 번들 분석 리포트

@github-actions
Copy link

github-actions bot commented Dec 6, 2025

⚡ Lighthouse 성능 분석 결과

📊 전체 평균 점수

지표 점수
🚀 Performance 73점
♿ Accessibility 87점
✅ Best Practices 100점
🔍 SEO 100점

📈 측정 현황

  • 측정 성공: 15/16 페이지
  • 상태: success

📄 페이지별 상세 분석

🏠 커뮤니티 페이지: /main/community

지표 점수
🚀 Performance 65점
♿ Accessibility 80점
✅ Best Practices 100점
🔍 SEO 100점

📊 상세 분석 보기

👥 창업자 페이지: /main/founder

지표 점수
🚀 Performance 75점
♿ Accessibility 87점
✅ Best Practices 100점
🔍 SEO 100점

📊 상세 분석 보기

🏡 홈 페이지: /main/home

지표 점수
🚀 Performance 75점
♿ Accessibility 91점
✅ Best Practices 100점
🔍 SEO 100점

📊 상세 분석 보기

🗺️ 지도 페이지: /main/maps

지표 점수
🚀 Performance 75점
♿ Accessibility 87점
✅ Best Practices 100점
🔍 SEO 100점

📊 상세 분석 보기

👤 프로필 페이지: /main/profile

지표 점수
🚀 Performance 75점
♿ Accessibility 88점
✅ Best Practices 100점
🔍 SEO 100점

📊 상세 분석 보기

🔗 전체 상세 분석 결과

📊 전체 상세 Lighthouse 분석 결과 보기

📄 측정된 페이지

  • /main/community
  • /main/founder
  • /main/home
  • /main/maps
  • /main/profile

모든 페이지에서 성능 측정이 완료되었습니다.


🤖 자동 생성된 Lighthouse 성능 리포트

@github-actions
Copy link

github-actions bot commented Dec 6, 2025

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

이 PR은 @soso/ui 패키지의 초기 설정과 Button 컴포넌트를 추가하는 작업입니다. tsup 빌드 시스템, Vitest 테스트 환경, 그리고 프로덕션급 React 컴포넌트 라이브러리를 위한 기본 인프라를 구축했습니다.

주요 변경사항:

  • @soso/ui 패키지 설정: ESM/CJS 이중 지원, TypeScript 타입 선언, npm 배포 준비
  • tsup 빌드 시스템 구축: esbuild 기반 초고속 빌드, tree-shaking 지원
  • Vitest 테스트 환경: React Testing Library 통합, 19개 단위 테스트 작성
  • Button 컴포넌트 구현: variant, size, loading 상태 지원, 접근성 고려
  • 패키지 매니저 버전 업그레이드 및 설정 조정

Reviewed changes

Copilot reviewed 24 out of 25 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/ui/package.json UI 패키지 메타데이터, exports 설정, 의존성 정의
packages/ui/tsconfig.json TypeScript 컴파일러 설정, path alias 및 타입 정의
packages/ui/tsup.config.ts tsup 빌드 설정 (ESM/CJS/DTS 생성)
packages/ui/vitest.config.ts Vitest 테스트 환경 설정 (jsdom, coverage)
packages/ui/src/components/Button/Button.tsx Button 컴포넌트 구현 (variant, size, loading 지원)
packages/ui/src/components/Button/Button.test.tsx Button 컴포넌트 단위 테스트 (19개 테스트)
packages/ui/src/components/Pressable/Pressable.tsx Press 애니메이션 래퍼 컴포넌트
packages/ui/src/hooks/useTap.ts 포인터 이벤트 처리 훅
packages/ui/src/hooks/useLoadingDelay.ts 로딩 지연 처리 훅
packages/ui/src/utils/cn.ts Tailwind className 병합 유틸리티
packages/ui/src/constants/animation.ts 애니메이션 토큰 정의
packages/ui/src/test/setup.ts Vitest 전역 설정 (jest-dom matchers)
packages/ui/src/index.ts 패키지 메인 export 파일
packages/ui/.npmignore npm 배포 제외 파일 설정
packages/ui/.eslintrc.cjs ESLint 설정 (라이브러리용)
packages/ui/README.md 패키지 문서화
packages/eslint-config/library.cjs 라이브러리 전용 ESLint 규칙 추가
package.json 패키지 매니저 버전 업데이트, engines 설정, overrides 추가
.npmrc pnpm 버전 업데이트
apps/web/package.json @types/node 버전 업데이트
apps/web/.eslintrc.cjs ESLint 설정 단순화

Comment on lines +20 to +29
"./components/*": {
"import": {
"types": "./dist/components/*.d.mts",
"default": "./dist/components/*.mjs"
},
"require": {
"types": "./dist/components/*.d.ts",
"default": "./dist/components/*.js"
}
}
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subpath exports 패턴 ./components/*가 설정되어 있으나, tsup 빌드 설정(tsup.config.ts)에서는 entry: ['src/index.ts']만 지정되어 있어 개별 컴포넌트 파일이 생성되지 않습니다.

현재 빌드로는 dist/components/ 디렉토리가 생성되지 않아 이 export가 작동하지 않습니다.

해결 방법:

  1. tsup.config.ts의 entry에 개별 컴포넌트를 추가하거나
  2. 이 subpath export를 제거하거나
  3. 번들러가 tree-shaking을 처리하도록 메인 export만 사용하시기 바랍니다.
Suggested change
"./components/*": {
"import": {
"types": "./dist/components/*.d.mts",
"default": "./dist/components/*.mjs"
},
"require": {
"types": "./dist/components/*.d.ts",
"default": "./dist/components/*.js"
}
}

Copilot uses AI. Check for mistakes.
Comment on lines 49 to +50
"@lhci/cli": "^0.15.1",
"eslint": "^8.56.0",
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eslint가 devDependencies 목록의 중간에 추가되어 있어 알파벳 순서가 깨졌습니다. 일관성을 위해 @eslint/eslintrc 다음에 위치시키시기 바랍니다.

Suggested change
"@lhci/cli": "^0.15.1",
"eslint": "^8.56.0",
"eslint": "^8.56.0",
"@lhci/cli": "^0.15.1",

Copilot uses AI. Check for mistakes.
delayMs: 200,
});

const isDisabled = disabled;
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] isDisabled 변수가 단순히 disabled를 할당받고 있어 불필요해 보입니다. disabled를 직접 사용하는 것이 더 명확합니다.

만약 향후 isLoading 상태도 포함한 복합 조건이 필요하다면 주석으로 의도를 명시하는 것을 권장합니다.

Copilot uses AI. Check for mistakes.
});

return () => timers.forEach((timer) => clearTimeout(timer));
}, [isLoading, delayMs]);
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useEffect의 의존성 배열에 delayMs가 포함되어 있는데, 이 값이 배열일 경우 매 렌더링마다 새로운 참조가 생성되어 effect가 불필요하게 재실행될 수 있습니다.

해결 방법:

  1. delayMsuseMemo로 감싸거나
  2. 의존성 배열에서 JSON.stringify(delayMs)를 사용하거나
  3. 또는 ESLint 규칙을 무시하고 안정적인 값만 의존성에 포함시키도록 문서화하시기 바랍니다.
Suggested change
}, [isLoading, delayMs]);
}, [isLoading, JSON.stringify(delayMs)]);

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

github-actions bot commented Dec 6, 2025

@github-actions
Copy link

github-actions bot commented Dec 6, 2025

Copy link
Member

@youdaeng2 youdaeng2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공통 UI 패키지 구조랑 tsup/vitest 세팅까지 한 번에 잡아주셔서 감사합니다.
처음 접하는 내용이 많아서 완전히 이해했다고 할 순 없지만.. 전체적인 흐름은 파악할 수 있었습니다!

이전에 말씀해주신 것처럼 나중에는 web 쪽에서도 @soso/ui의 Button을 import해서 사용하는 방향으로 가져가실 예정이신 걸까요?

고생하셨습니다!!!

@github-actions
Copy link

@github-actions
Copy link

@DreamPaste DreamPaste merged commit 4f92602 into dev Dec 23, 2025
4 checks passed
@DreamPaste DreamPaste deleted the feat/SOS-47-package-ui-init branch December 23, 2025 13:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feat 💡 새로운 기능을 구현하고 추가합니다! 휘건

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UI 패키지 기본 설정 및 빌드 시스템 구축

3 participants