Development
Chakra UI 3 버전 Migration 이야기
2025-02-05

프론트엔드 애플리케이션을 개발할 때에는 Charkra UI라는 컴포넌트 라이브러리를 사용하곤 합니다. 컴포넌트 스타일링 값은 React Props로 넘깁니다. 이러한 특징으로 Typescript와 함께 사용하면 알지 못했던 CSS 요소까지 쉽게 탐색하고 사용할 수 있는 장점이 있는 것 같습니다. 다른 라이브러리를 이처럼 열심히 사용해보지는 않아서 비교는 불가하지만 적어도 제 손맛에는 가장 맞는 라이브러리인 것 같습니다.

이거 없으면 프론트개발 못합니다..
Chakra 3.0 등장
2024년 10월, 즉 제가 한참 학교공부를 하고 있을 시간에 3.0 버전이 출시되었습니다. 당시에는 출시된 지도 몰랐으며 최근에 다른 프로젝트를 하면서 3.0의 등장을 알게 되었습니다. 이미 이 시점에는 3.5.1 버전이 나온 상태였습니다.
개발 중 뭔가 예전이랑 UI가 조금씩 다른 느낌이 있어서 어색함을 느끼던 찰나 큰 버전 업데이트가 있어서 그랬다는 것을 인지했습니다. 이후 문서를 차근차근 살펴보니 새로운 기능이 많아져서 괜시리 설레었습니다. 이 글에서는 몇개만 살펴보기로 하겠습니다.
For
컴포넌트의 목록을 렌더링할 때 사용하는 컴포넌트입니다.
import { Box, For, Stack, Text } from "@chakra-ui/react";
const Demo = () => {
return (
<Stack>
<For
each={[
{ name: "Naruto", powers: ["Shadow Clone", "Rasengan"] },
{ name: "Sasuke", powers: ["Chidori", "Sharingan"] },
{ name: "Sakura", powers: ["Healing", "Super Strength"] },
]}
>
{(item, index) => (
<Box borderWidth="1px" key={index} p="4">
<Text fontWeight="bold">{item.name}</Text>
<Text color="fg.muted">Powers: {item.powers.join(", ")}</Text>
</Box>
)}
</For>
</Stack>
);
};어떤 값을 토대로 목록을 렌더링한다는 semantic한 의미가 조금 더 드러나는 것 같지만 특별하게 써야할 이유를 잘 모르겠습니다. 그냥 map 함수를 쓸 때보다 코드가 줄어들지도 않는 것 같고, 오히려 코드가 더 복잡해지는 것 같아서 잘 안쓰게 되는 컴포넌트였습니다.
QR Code
import { QrCode } from "@chakra-ui/react"
const Demo = () => {
return (
<QrCode.Root value='https://www.petefolio.xyz'>
<QrCode.Frame>
<QrCode.Pattern />
</QrCode.Frame>
</QrCode.Root>
);
}이젠 컴포넌트 기반으로 QR 코드도 만들 수 있게 됩니다. 링크만 넣어주면 뚝딱입니다. 정말 간편하게 만들 수 있지만 딱히 사용할 기회가 없을 것 같기도 합니다. 이번 프로젝트에 어떻게든 억지로 한번 넣어봐야겠습니다.
Timeline

Timeline 컴포넌트입니다. 블로그의 About me 페이지에 넣으면 찰떡일 것 같다는 생각을 했습니다. 사용하기 어렵지는 않았지만 좌측 동그라미의 크기 변경 기능에 제한이 있었고, 임의로 조정하면 line이 어긋나는 문제가 발생하였습니다.
Timeline을 비롯한 몇몇 컴포넌트들은 '@chakra-ui/react' 로 import하는 것 대신에, chakra-cli를 사용하여 소스코드를 로컬 프로젝트에 생성하는 방식으로 사용할 것을 문서에서 명시하고 있었습니다. 왜인지는 잘 모르겠습니다. 아마 아직 실험적인 컴포넌트들은 안정성이 떨어져 사용자에게 커스터마이징을 맡기기 위함이었을까요? 아무튼 저는 타임라인을 About Me 페이지에서만 사용할 것이었으므로 cli로 생성된 컴포넌트 자체를 수정하여 좌측 동그라미 크기에 맞게 선을 배치시켰습니다.

기존 디자인보다 훨씬 보기 좋아진 것 같아 기분이 좋습니다.
Migration을 하는 와중에도 업데이트는 계속된다.
Timeline을 블로그에 너무 넣고 싶어서 라이브러리 버전 마이그레이션을 최근 5일에 거쳐 수행했습니다. 버전 업데이트를 하는 순간 블로그 앱은 실행도 되지 않았고, 꼬박 2시간을 코드를 고쳐서야 겨우 화면을 볼 수 있었습니다. 물론 UI는 다 깨진 상태로요.
정말 정말 많은 코드를 고쳤습니다.
오류가 발생하여 화면을 볼 수 없었던 이유는 cli로 설치한 소스코드를 import 해야하는 몇몇 라이브러리가 있었기 때문입니다. select, tag, toaster 등이 그랬습니다. 이런 방식을 snippet이라고 문서에서 본 것 같은데, 정확히 왜 이런 방식을 쓰는지는 나중에 한번 알아봐야겠습니다.
2버전에서 토스트를 띄우기 위해 사용했던 useToast도 없어졌습니다. 이는 toaster 컴포넌트를 가져와 완전히 새롭게 구현해야 했습니다.
색상을 부여하는 속성이었던 colorScheme를 전부 colorPalette로 바꾸어야 했습니다. 다행히도 이는 Import 문제와는 상관 없었기에 화면을 보면서 색상이 적용되지 않은 것만 바꿔주었습니다. Palette라는 단어 배열이 뭔가 어색해 계속 Pallete로 작성했다가 컴파일 에러를 여럿 보았습니다
또한 2버전에서는 <Show above='md'>...</Show> 와 같은 방식을 통해 화면 크기를 기준으로 컴포넌트를 조건부 렌더링 할 수 있었는데, 이 기능이 모두 사라져버렸습니다. 모든 코드에서 이 컴포넌트를 없애주고, display에 조건부 속성을 주는 방식으로 기존과 같은 반응형을 유지시켜줘야 했습니다.
구분선인 Divider는 Separator로 바뀌었습니다. 기능은 유사한 것 같습니다.
또한 계층 구조를 갖는 여러 컴포넌트에 공통 컴포넌트 이름을 공유하도록 만드는 패턴이 나타났습니다. 이 부분이 가장 시간을 많이 쏟게 하면서도 가장 맘에 드는 부분이기도 합니다. 내부에 필요한 요소를 직관적으로 불러올 수도 있고 잘못된 요소를 가져다 쓰는 일도 방지해주기 때문입니다. 상단의 import 문들이 깔끔해지는 효과도 있습니다.
//2.x
<UnorderedList>
<ListItem>
</ListItem>
</UnorderedList>
//3.x
<List.Root as='ol'>
<List.Item>
</List.Item>
</List.Root>이렇게 며칠간 마이그레이션을 하는데, 그 사이에 3.5.1 이었던 버전은 3.6.0, 더 나아가 3.7.0까지 되었습니다. 그간의 변경 때문에 snippet 방식으로 바꿔주었던 Tag 컴포넌트를 또 다시 원상태로 바꿔야하는 이상한 일까지 겪었습니다.

3일 전

18시간 전
이네들은 업데이트가 왜이리 잦을까요? 속도에 따라가려면 부단히 공부해야할 것 같습니다.
아쉬운 점
크기
전반적으로 컴포넌트 및 글씨 크기가 작아졌습니다. 기존 버전에서의 크기를 수치로 기억하지는 못하지만, 같은 사이즈 이름 (Ex. 'md', 'xl') 을 가진 글자 혹은 버튼 등에서 확연히 크기가 작아짐을 느꼈습니다. 비교적 큰 컴포넌트를 디자인할 때 기존에는 '2xl', '3xl' 등으로 작성했고 그것에 만족했었는데, 3버전이 된 이후로는 사이즈명으로 충분한 크기가 나오지 않아 구체적인 픽셀을 지정해주어야 했습니다. 구체적인 픽셀 작성은 모바일로 바뀔 때에 크기까지 지정하도록 요구하기에 굉장히 번거로운 일이 되었습니다.
기본 색상
처음에는 뭔가 라이브러리 설치에 오류가 생긴줄 알았습니다. 버튼의 기본 색상이 새까만색으로 계속 나타났던 겁니다. colorPalette에 gray, white, black을 줘봐도 변함이 없었습니다. 혹시 theme 설정이 잘못되었나 하고 테마 설정 문서도 한참을 찾아보았습니다.

알고보니 그냥 기본 색상이 블랙이 되어버린 것이었습니다. 2버전에서 기본 색상은 회색이어서 그럭저럭 블로그와 어울려서 사용했지만, 블랙이 되고나니 좀 보기 싫어서 모든 Button에 색상 속성을 바꾸게 되었습니다. 2버전의 버튼과 유사한 디자인은 Button의 기본 colorPalette에 variant를 subtle혹은 surface를 주어 구현할 수 있었습니다.