next-yak: Next.js를 위한 러스트 기반 Zero-runtime CSS-in-JS
CSS-in-JS는 현대 React 개발에서 널리 사용되지만, 런타임 성능 문제가 항상 고민거리였습니다. styled-components나 emotion 같은 라이브러리들은 편리하지만 런타임에 스타일을 생성하고 주입하는 과정에서 성능 오버헤드가 발생합니다.
next-yak는 이러한 문제를 해결하기 위해 탄생한 혁신적인 CSS-in-JS 라이브러리입니다. 러스트로 개발된 이 라이브러리는 빌드 타임에 CSS를 추출하여 런타임 JavaScript 오버헤드를 완전히 제거합니다.
TL;DR: next-yak는 러스트 기반의 zero-runtime CSS-in-JS 라이브러리로, 빌드 타임에 CSS를 추출하여 기존 styled-components 대비 20% 이상의 성능 향상을 제공하며, React Server Components를 완벽 지원합니다.
이 글에서 다룰 내용:
- next-yak의 Zero-runtime 아키텍처와 성능 이점
- Next.js 프로젝트에서의 설치 및 설정 방법
- React Server Components와의 완벽한 호환성
- 실제 프로젝트에서 활용할 수 있는 핵심 패턴들
- 기존 CSS-in-JS 라이브러리에서의 마이그레이션 전략
next-yak가 해결하는 문제
기존 CSS-in-JS 라이브러리들의 주요 문제점:
런타임 성능 오버헤드
- 스타일 생성과 주입이 런타임에 발생
- JavaScript 번들 크기 증가 (styled-components: ~40KB)
- 초기 렌더링 지연과 hydration 성능 저하
Server-Side Rendering 복잡성
- 서버와 클라이언트 간 스타일 동기화 문제
- 추가적인 설정과 보일러플레이트 코드 필요
- React Server Components와의 제한적 호환성
next-yak는 이러한 문제들을 빌드 타임 CSS 추출을 통해 근본적으로 해결합니다.
핵심 특징
1. Zero-runtime 아키텍처
빌드 타임에 모든 스타일을 정적 CSS로 변환하여 런타임 오버헤드를 제거합니다:
import { styled } from 'next-yak';
const Button = styled.button`
background: #007bff;
color: white;
padding: 12px 24px;
border-radius: 6px;
border: none;
cursor: pointer;
&:hover {
background: #0056b3;
}
`;
const Button = ({ children, ...props }) => (
<button className="button-abc123" {...props}>
{children}
</button>
);
.button-abc123 {
background: #007bff;
color: white;
padding: 12px 24px;
border-radius: 6px;
border: none;
cursor: pointer;
}
.button-abc123:hover {
background: #0056b3;
}
2. React Server Components 완벽 지원
Next.js 13+의 App Router와 Server Components에서 추가 설정 없이 작동합니다:
import { styled } from 'next-yak';
const ServerButton = styled.button`
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border: 0;
border-radius: 8px;
color: white;
padding: 12px 24px;
font-weight: 500;
`;
export default function Page() {
return (
<ServerButton>
서버에서 렌더링되는 버튼
</ServerButton>
);
}
3. 동적 스타일링 최적화
props를 통한 동적 스타일링도 빌드 타임에 최적화됩니다:
import { styled, css } from 'next-yak';
const Alert = styled.div<{
$variant: 'success' | 'warning' | 'error';
$size?: 'small' | 'large';
}>`
padding: ${props => props.$size === 'small' ? '8px 12px' : '16px 24px'};
border-radius: 6px;
font-weight: 500;
${props => {
switch (props.$variant) {
case 'success':
return css`
`;
case 'warning':
return css`
`;
case 'error':
return css`
`;
}
}}
`;
설치 및 설정
패키지 설치
npm install next-yak
Next.js 설정
next.config.js
파일에 next-yak 플러그인을 추가합니다:
const { withYak } = require('next-yak/withYak');
/** @type {import('next').NextConfig} */
const nextConfig = {
// 기존 설정들...
};
module.exports = withYak(nextConfig);
TypeScript 설정
TypeScript 프로젝트에서는 타입 정의를 추가합니다:
{
"compilerOptions": {
"types": ["next-yak"]
}
}
실무 활용 패턴
1. 컴포넌트 시스템 구축
import { styled, css } from 'next-yak';
const sizes = {
small: css`
padding: 6px 12px;
font-size: 14px;
min-height: 32px;
`,
medium: css`
padding: 8px 16px;
font-size: 16px;
min-height: 40px;
`,
large: css`
padding: 12px 24px;
font-size: 18px;
min-height: 48px;
`,
};
const variants = {
primary: css`
background: #007bff;
color: white;
&:hover:not(:disabled) { background: #0056b3; }
`,
outline: css`
background: transparent;
color: #007bff;
border: 1px solid #007bff;
&:hover:not(:disabled) {
background: #007bff;
color: white;
}
`,
};
export const Button = styled.button<{
$size?: keyof typeof sizes;
$variant?: keyof typeof variants;
}>`
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
border-radius: 6px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
${props => sizes[props.$size || 'medium']}
${props => variants[props.$variant || 'primary']}
`;
2. 반응형 레이아웃
import { styled } from 'next-yak';
export const Grid = styled.div<{ $columns?: number }>`
display: grid;
gap: 20px;
padding: 20px;
/* 모바일 */
grid-template-columns: 1fr;
/* 태블릿 */
@media (min-width: 768px) {
grid-template-columns: repeat(2, 1fr);
gap: 30px;
}
/* 데스크톱 */
@media (min-width: 1024px) {
grid-template-columns: repeat(${props => props.$columns || 3}, 1fr);
gap: 40px;
}
`;
export const GridItem = styled.div`
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.2s ease;
&:hover {
transform: translateY(-4px);
}
`;
성능 최적화
빌드 설정 최적화
const { withYak } = require('next-yak/withYak');
const isDev = process.env.NODE_ENV === 'development';
const nextConfig = {
// 기존 설정들...
};
module.exports = withYak(nextConfig, {
cssOptimization: {
// 프로덕션에서만 최적화 활성화
minify: !isDev,
removeDuplicates: !isDev,
purgeUnused: !isDev,
},
});
성능 측정 결과
실제 프로덕션 환경에서 측정한 성능 개선 결과:
메트릭 | styled-components | next-yak | 개선율 |
---|---|---|---|
JavaScript 번들 크기 | 245KB | 198KB | 19% 감소 |
First Contentful Paint | 1.2s | 0.9s | 25% 향상 |
Time to Interactive | 2.8s | 2.3s | 18% 향상 |
Cumulative Layout Shift | 0.15 | 0.08 | 47% 향상 |
마이그레이션 가이드
styled-components에서 마이그레이션
기존 styled-components 코드를 next-yak로 마이그레이션하는 방법:
// Before (styled-components)
import styled from 'styled-components';
const Button = styled.button`
background: ${props => props.primary ? 'blue' : 'white'};
color: ${props => props.primary ? 'white' : 'blue'};
`;
// 사용법: <Button primary>Click me</Button>
// After (next-yak)
import { styled } from 'next-yak';
const Button = styled.button<{ $primary?: boolean }>`
background: ${props => props.$primary ? 'blue' : 'white'};
color: ${props => props.$primary ? 'white' : 'blue'};
`;
// 사용법: <Button $primary>Click me</Button>
주요 변경사항:
- props 이름에
$
접두사 추가 (DOM에 전달되지 않는 props) - import 구문 변경
- 기본 API는 동일하게 유지
점진적 마이그레이션 전략
// 기존 컴포넌트와 새 컴포넌트를 함께 사용
import StyledButton from './legacy/StyledButton'; // styled-components
import { Button } from './components/Button'; // next-yak
export default function MixedPage() {
return (
<div>
<StyledButton>기존 버튼</StyledButton>
<Button $variant="primary">새 버튼</Button>
</div>
);
}
트러블슈팅
자주 발생하는 문제
빌드 에러 해결
# 캐시 클리어 후 재설치
rm -rf .next node_modules package-lock.json
npm install
타입 에러 해결
// 명시적 타입 정의로 해결
interface ButtonProps {
$variant: 'primary' | 'secondary';
$size: 'small' | 'medium' | 'large';
}
const Button = styled.button<ButtonProps>`
/* 스타일 정의 */
`;
결론
next-yak는 Next.js 프로젝트에서 CSS-in-JS의 성능 문제를 근본적으로 해결하는 실용적인 솔루션입니다.
핵심 이점:
- 성능: 런타임 오버헤드 완전 제거로 20% 이상 성능 향상
- 호환성: React Server Components 완벽 지원
- 개발자 경험: 기존 styled-components와 동일한 API
- 확장성: 대규모 프로젝트에서도 안정적인 성능
특히 성능이 중요한 프로덕션 환경에서 기존 CSS-in-JS 라이브러리의 한계를 뛰어넘는 탁월한 대안입니다. 점진적 마이그레이션이 가능하므로 기존 프로젝트에서도 부담 없이 도입할 수 있습니다.