1. Accordion부터 Button까지, 다른 라이브러리에서 가져온 장점들
오늘은 제가 개발한 React 컴포넌트 라이브러리에 관한 이야기를 해보려고 합니다. 다양한 컴포넌트 라이브러리들을 연구하면서 각각의 장점을 모으고 제 스타일로 재해석한 과정을 공유하고자 합니다.
Accordion 컴포넌트의 재해석
제 라이브러리의 Accordion 컴포넌트는 여러 유명 라이브러리의 장점을 조합했습니다.
Radix UI에서 가져온 장점
Radix UI의 Accordion은 접근성에 매우 강점이 있습니다. WAI-ARIA 디자인 패턴을 준수하고, 키보드 조작성이 매우 뛰어납니다.
다음 기능들을 제 라이브러리에 적용했습니다:
- 헤더 및 패널 관계를 명확히 정의하는 접근성 구조
- aria-expanded, aria-controls, aria-disabled 속성을 활용한 스크린 리더 지원
- 키보드 탐색 지원 (Tab, Enter, Space, ArrowDown, ArrowUp, Home, End)
// Radix UI의 접근성 코드를 참고하여 구현한 부분
<button
id={headerId}
className={`accordion-title ${classNames.title || ""}`}
style={styles.title}
onClick={() => !item.disabled && onToggle(index)}
onKeyDown={handleKeyDown}
aria-expanded={isOpen}
aria-controls={panelId}
aria-disabled={item.disabled}
disabled={item.disabled}
tabIndex={item.disabled ? -1 : 0}
>
{item.title}
{/* 아이콘 */}
</button>
Mantine에서 가져온 장점
Mantine의 Accordion은 사용자 경험에 초점을 맞춘 방식이 인상적이었습니다. 특히 다음 기능들을 제 라이브러리에 적용했습니다:
- 직관적인 Props API 구조와 명확한 문서화
- 중첩 아코디언 지원
- 애니메이션 커스터마이징이 쉬운 구조
// Mantine 스타일의 컨텍스트 관리 방식을 참고하여 구현
const AccordionContext = createContext<AccordionContextValue | null>(null);
const useAccordion = () => {
const context = useContext(AccordionContext);
if (!context) {
throw new Error("useAccordion must be used within an Accordion");
}
return context;
};
ShadCN UI에서 가져온 장점
ShadCN UI의 가장 큰 특징은 고도로 커스텀 가능한 구조와 Tailwind CSS와의 통합입니다. 다음 요소들을 제 라이브러리에 적용했습니다:
- 유연한 커스터마이징 시스템
- 최소한의 스타일링과 확장 가능한 인터페이스
- 쉬운 테마 적용 가능성
// ShadCN UI의 커스텀 스타일링 접근 방식 참고
const animationStyle = {
...styles.content,
'--accordion-animation-duration': typeof animationDuration === 'number'
? `${animationDuration}ms`
: `var(--accordion-duration-${animationDuration || 'normal'})`,
};
Button 컴포넌트의 재해석
Button 컴포넌트도 여러 라이브러리의 장점을 조합했습니다.
여러 라이브러리에서 가져온 장점들:
- 구조적 명확성: Mantine의 깔끔한 컴포넌트 구조를 참고했습니다.
- 다양한 변형: Material UI와 ShadCN의 다양한 버튼 변형(variant)을 참고했습니다.
- 접근성 고려: Radix UI의 접근성 기능(aria 속성, 키보드 지원)을 적용했습니다.
- 스타일 유연성: emotion/styled에서 영감을 받은 CSS 변수 기반 스타일링 시스템을 구축했습니다.
// 여러 라이브러리의 장점을 조합한 Button 컴포넌트
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(({
children,
variant = 'primary',
size = 'md',
fullWidth = false,
isLoading = false,
loadingText,
// ... 다양한 옵션들
}, ref) => {
// 복합적인 클래스명 생성
const buttonClasses = `
button
button-${variant}
button-${size}
${fullWidth ? 'button-full-width' : ''}
${isLoading ? 'button-loading' : ''}
${rounded ? 'button-rounded' : ''}
${elevated ? 'button-elevated' : ''}
${className}
`.trim();
// 접근성 속성과 함께 반환
return (
<button
ref={ref}
className={buttonClasses}
disabled={disabled || isLoading}
type={type}
aria-busy={isLoading}
aria-disabled={disabled || isLoading}
{...rest}
>
{/* 로딩 상태 및 아이콘 처리 */}
</button>
);
});
2. 트리쉐이킹으로 사용량 최적화하기
트리쉐이킹은 모던 자바스크립트 애플리케이션에서 필수적인 최적화 기법입니다. 제 라이브러리에서는 트리쉐이킹을 적용하여 번들 사이즈를 크게 줄일 수 있었습니다.
트리쉐이킹 적용 전
트리쉐이킹을 적용하기 전에는 라이브러리 전체가 하나의 번들로 제공되었습니다. 이는 사용하지 않는 컴포넌트까지 모두 포함된다는 의미였습니다.
트리쉐이킹 적용 후
트리쉐이킹을 적용한 후에는 실제 사용하는 컴포넌트만 번들에 포함되어 크게 최적화되었습니다
예를 들어, Button과 Input 컴포넌트만 사용하는 프로젝트의 경우:
- 트리쉐이킹 전: 520KB (전체 라이브러리)
- 트리쉐이킹 후: 64KB (Button 28KB + Input 36KB)
약 87.7%의 번들 크기가 감소한 것을 볼 수 있습니다!
3. 트리쉐이킹 적용 과정과 결과
트리쉐이킹 적용 방법
트리쉐이킹을 적용하기 위해 다음과 같은 변경을 진행했습니다:
- ESM 모듈 방식 채택: CommonJS 대신 ESM(ECMAScript Modules) 방식을 사용했습니다
// package.json
{
"type": "module",
"exports": {
".": {
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
}
},
"sideEffects": false
}
- 개별 컴포넌트 엔트리포인트 제공: 각 컴포넌트를 개별적으로 가져올 수 있도록 했습니다.
// 이전 방식
import { Button, Input, Accordion } from 'react-common-components-library';
// 트리쉐이킹이 가능한 방식
import Button from 'react-common-components-library/Button';
import Input from 'react-common-components-library/Input';
- sideEffects 속성 설정: package.json에 "sideEffects": false를 추가하여 웹팩에게 사이드 이펙트가 없음을 알렸습니다.
- 모듈 구조 최적화: 내부 의존성을 명확히 하고 순환 참조를 제거했습니다.
트리쉐이킹 적용 결과
트리쉐이킹을 적용한 후, 다양한 사용 시나리오에서 번들 크기 변화를 측정했습니다:
| 사용 시나리오 | 트리쉐이킹 전 | 트리쉐이킹 후 | 감소율 |
|------------|------------|------------|-------|
| 전체 라이브러리 | 520KB | 520KB | 0% || Button만 사용 | 520KB | 28KB | 94.6% |
| Input만 사용 | 520KB | 36KB | 93.1% |
| Button + Dialog 사용 | 520KB | 53KB | 89.8% |
| 대규모 앱(10개 컴포넌트) | 520KB | 218KB | 58.1% |
특히 소규모 앱이나 특정 컴포넌트만 사용하는 경우 90% 이상의 번들 크기 감소를 달성할 수 있었습니다.
결론
여러 유명 라이브러리의 장점을 연구하고 조합하여 제 라이브러리를 만들었습니다. Radix UI의 접근성, Mantine의 사용자 경험, ShadCN UI의 커스터마이징 기능 등 각 라이브러리의 강점을 취하면서 트리쉐이킹을 통한 최적화까지 적용했습니다.이 과정에서 얻은 가장 큰 교훈은 "좋은 컴포넌트는 단순히 잘 작동하는 것을 넘어, 접근성, 성능, 확장성을 두루 갖추어야 한다"는 것입니다. 앞으로도 계속 발전시켜 나가겠습니다!
'생각 > javascript' 카테고리의 다른 글
트리쉐이킹(Tree Shaking) 테스트 결과 보고서 (0) | 2025.03.25 |
---|---|
[리액트 컴포넌트 라이브러리 고도화] 전체 컴포넌트 리팩토링 대장정 (0) | 2025.03.17 |
순열과 조합(코딩테스트) (0) | 2025.02.21 |
코딩테스트 알고리즘 정리 (0) | 2025.02.17 |
Chart.js (0) | 2023.06.23 |