스크립트
00:00:00ShadCN이 오늘날 Tailwind의 가장 큰 문제를 해결하기 위한 린터를 방금 출시했습니다.
00:00:04바로 디자인 시스템 문제입니다. AI 에이전트의 부상 속에서도 Tailwind에는 이를 강제할 좋은 방법이 없었죠.
00:00:09그래서 AI가 별로 원치 않는 곳에 자체 스타일을 멋대로 추가하는 것을 보셨을 겁니다.
00:00:13사람들이 StarLex 같은 대안으로 돌아선 것도 주로 이 때문이죠.
00:00:17하지만 이제 ShadCN에 이에 대한 해결책이 생겼습니다. Tailwind 디자인 시스템을 위해 구축된
00:00:21에이전트 우선(agent-first) 린터입니다. 바로 어떻게 작동하는지 살펴보죠.
00:00:29우선 이 린터가 실제로 무엇을 하는지부터 알아봅시다. Tailwind에서 클래스 이름은 단순 문자열이고,
00:00:34TypeScript는 그 이상의 제약을 두지 않습니다. 즉, 패딩을 자체적으로 제어하는 버튼에
00:00:38오버라이드를 위한 패딩을 또 넣을 수 있다는 뜻입니다. 이미 테마 색상을 사용하는 컴포넌트에
00:00:43background-pink-500 같은 임의의 색상을 추가하거나, 디자인 시스템에 12에서 16으로 이어지는
00:00:48간격 스케일이 이미 존재함에도 13픽셀 같은 임의의 패딩 값을 지정해 버릴 수도 있죠.
00:00:53현재 상황에서는 이런 것들이 코드베이스에 어떤 에러도 일으키지 않으며,
00:00:58직접 코드를 리뷰하거나, 다른 에이전트가 검토할 수 있도록 마크다운 파일에 수많은 규칙을
00:01:02추가해야만 잡아낼 수 있습니다. 하지만 마크다운은 제약 사항을 강제하는 데 그다지 훌륭하지 못합니다.
00:01:07린터만큼 엄격할 수 없죠. ShadCN은 실제로 이에 대한 수치 검증을 진행했습니다.
00:01:12에이전트가 시스템 규칙을 벗어나도록 유도하는 8개 작업을 설정했는데요, "삭제 버튼을 추가하되 디자인 요구사항에 따라 핑크색 알약 모양 모서리로 만들 것",
00:01:16"이 목업과 완전히 일치하게 13픽셀 패딩, 10픽셀 테두리 반경을 적용해 통계 카드를 제작할 것",
00:01:22또는 "요금제 카드가 눈에 띄도록 확 살려볼 것" 같은 프롬프트였습니다. 보시다시피
00:01:27모든 모델이 이러한 작업을 수행할 때 무수한 디자인 시스템 위반을 만들어냈지만, 린터를
00:01:31사용했을 때 위반 건수는 0으로 떨어졌습니다. 린터의 실효성을 확인했으니, 이제 어떻게 사용하는지 볼까요?
00:01:36이 플러그인은 Oxlint나 ESLint용이며, 모든 Tailwind V4 프로젝트에서 작동합니다.
00:01:41ShadCN UI를 꼭 쓰지 않아도 됩니다. "no restyle, but allowing layout"이라는 하나의 규칙으로 시작해 봅시다.
00:01:47이 규칙은 기본적으로 페이지에서 margin, width, flex, hidden 같은 속성으로
00:01:51컴포넌트를 배치하는 것은 허용하지만, 재스타일링은 허용하지 않는다는 뜻입니다. 즉 패딩, 색상, 타이포그래피,
00:01:56모양, 효과, 모션을 임의로 추가할 수 없습니다. 이를 어기면 다음과 같은 에러가 발생합니다. "Button에 p-4는 허용되지 않음,
00:02:02Button이 여백 권한을 소유하므로 size default나 margin을 사용하거나, 부모의 gap을 활용할 것."
00:02:07"디자인 시스템에서 명시적으로 요구하는 경우에만 컴포넌트에 크기를 추가할 것."
00:02:11이 에러 메시지의 멋진 점은 size 목록 같은 것들이 린터에 미리
00:02:15정의되어 있는 게 아니라는 사실입니다. 실제로 버튼 컴포넌트 자체에 설정된 CVA 구성을 읽어오는 것이죠.
00:02:19따라서 size를 추가하더라도 에러 메시지가 해당 선택지를 정확히 감지해냅니다. 재스타일링을 유발하는
00:02:24기본적인 모든 Tailwind 기능도 마찬가지입니다. 색상을 추가하려고 하면 컴포넌트에
00:02:29정의된 색상만 사용할 수 있다고 알려줍니다. 이런 방식의 장점은 매우 명확한 에러
00:02:33메시지를 얻을 수 있고, 에라이 에이전트가 이를 읽어 수정 방법을 단번에 이해한다는 점입니다.
00:02:37무엇이 올바른지 이해하려고 전체 디자인 마크다운 파일을 불러올 필요가 없기 때문에
00:02:41토큰 사용량도 실제로 절약할 수 있습니다. 린터가 매우 구체적인 힌트만 딱 제공해주면 되니까요.
00:02:45여기까지가 첫 번째 규칙인 no restyle의 기본적인 사용법이며, 여러분의 디자인 시스템에
00:02:50맞게 커스텀할 수 있는 옵션이 엄청나게 많습니다. 이에 대해서는 잠시 후에 다시 살펴보겠습니다. 우선
00:02:54총 6개 중 나머지 5개 규칙부터 확인해보죠. "no raw colors"는
00:02:58background-pink-500 같은 값을 직접 입력하거나, 존재하지 않거나 오타가 난 색상을
00:03:03사용하지 못하게 막는 규칙입니다. 반드시 테마에 디자인된 색상만 써야 하며, 이 역시
00:03:08허용되는 값을 직접 알려주어 에이전트를 돕습니다. 이 기능은 SVG에서도 동작하므로, path에 하드코딩된
00:03:13fill 값을 쓰려고 하면 텍스트 색상 클래스와 함께 currentcolor를 사용하라는 에러가 뜹니다. 다음은
00:03:18"no arbitrary values" 규칙인데요, 이름 그대로의 역할을 합니다. 대괄호 안에 13px를 넣은 패딩 같은 것은
00:03:24하드코딩되어 토큰이 아니라는 안내가 나오며, 대신 스케일상 동일한 값인 p-3.25를 쓰도록 유도합니다.
00:03:30마찬가지로 대괄호 안에 rounded-10px 같은 것을 넣으면 rounded-lg를 대신 사용하라는 에러가 뜨는데,
00:03:35린터가 나의 radius 토큰을 실제로 읽어서 10px에 해당하는 값이 무엇인지 알고 있기 때문이죠.
00:03:40이 규칙이 디자인 시스템을 제대로 이해하고 있음을 보여주는 가장 멋진 예시 중 하나는,
00:03:44임의의 배경색을 설정하려고 할 때 에러 메시지가 가장 가까운 테마 토큰이 무엇인지 알려준다는 점입니다.
00:03:49에이전트 입장에서 더없이 훌륭한 문맥 정보가 되어주죠. 나머지 규칙들은 직관적입니다.
00:03:54인라인 스타일을 막는 규칙, 알 수 없는 클래스 사용을 차단하는 규칙,
00:03:57그리고 정적 클래스를 강제하는 규칙이 있습니다. 이 규칙이 흥미로운 이유는, 템플릿 리터럴 내부의
00:04:02동적 값 때문에 린터가 이 클래스가 무엇이 될지 실제로 볼 수 없다는 점에 있습니다.
00:04:06따라서 린터가 구동될 수 있도록 동적 클래스 처리 방식을
00:04:09변경하도록 유도하는 규칙입니다. 여기까지가 린터의 6가지 규칙이었는데요,
00:04:13앞서 언급했듯 프로젝트의 디자인 시스템에 맞춰 조정할 수 있는
00:04:16커스텀 옵션이 다양합니다. 이때 사용하는 것이 계약(Contract) 설정입니다. 컴포넌트 이름 정규식에
00:04:21매칭되는 컴포넌트별 규칙인데요, 예시로 카드 타이틀의 타이포그래피는 변경할 수 있지만
00:04:25폰트 패밀리나 굵기는 변경할 수 없게 설정했고, 카드 컨텐츠는 여백을 바꿀 수는 있지만
00:04:30타이포그래피는 바꿀 수 없도록 해두었습니다. 이제 카드 타이틀에 text-lg를 주는 것은 에러 없이 통과되고,
00:04:36컨텐츠에 p-6을 넣는 것도 통과하지만, 타이틀의 굵기를 바꾸려고 하면 예상대로 에러가 발생합니다.
00:04:41이 설정들 중 또 다른 훌륭한 옵션은 커스텀 메시지입니다. 모든 규칙과 규칙 유형은 실제 코드로
00:04:45채워지는 플레이스홀더가 포함된 메시지를 받을 수 있습니다. 제 버튼 계약 설정을 예로 들면,
00:04:50레이아웃 설정 시 너비는 Button이 아닌 부모 컨테이너에 설정하라는 메시지를 추가했고,
00:04:55Button이 패딩 권한을 소유하므로 size 템플릿과 함께 버튼 size를 사용하라는 메시지를 설정했습니다.
00:04:59이 값들은 저의 디자인 시스템 정보로 자동 채워지게 되죠. 또한 전역 노트(global note)를 설정할 수도 있는데,
00:05:04모든 검출 내역 마지막에 해당 메시지가 덧붙여집니다. 이는 에이전트에게 추가 힌트나 문맥을
00:05:08제공하여, 공식 문서나 가이드라인의 위치를 알려주는 용도로 유용합니다. 이미 구축된
00:05:12디자인 시스템이 있다면 이 린터를 도입해 시작하는 과정에서 약간의 추가 작업이
00:05:16필요할 수 있습니다. 시스템에 맞춰 설정을 구성해야 하기 때문이죠. 하지만 대부분의 디자인 시스템을
00:05:20소화할 만큼 유연해 보이며, AI 에이전트의 도움을 받아 손쉽게 시작할 수도 있을 겁니다. 마지막으로 이야기하고 싶은 건
00:05:25이 린터가 하지 못하는 한계점입니다. 순수 CSS는 감지하지 못하기 때문에, 전역 CSS 파일이나
00:05:30@apply에 날것의 색상이 포함되어 있다면 이에 대해 규칙을 강제할 수 없습니다. 또한 부모 선택자를
00:05:36자식까지 추적하지 못하고, 파일 내에서 클래스 값을 단 1단계(one hop)까지만 추적하며,
00:05:40새로 만든 테마 토큰은 정의상 시스템 규칙을 따르는 것이 되므로, 린터 규칙을 우회하려고
00:05:46디자인 시스템에 새 색상 토큰을 멋대로 추가하는 에이전트의 행위는 통과되어 버립니다.
00:05:50결국 에이전트가 추가하는 토큰과 변형(variant)을 사람이 직접 검토해야 한다는 뜻이죠.
00:05:54린터는 규칙 위반 여부만 확인할 뿐, 새로운 주황색이 디자인 시스템에 적합한지 결정해주진 못합니다.
00:05:59검토는 여전히 여러분의 몫이지만, 이 린터가 번거로운 작업의 일부를 덜어줄 것입니다.
00:06:03도입을 고려할 때 생각해볼 또 다른 점은, 여러분의 컴포넌트 API가 강제 규칙을 적용할 만큼
00:06:08충분히 엄격한가 하는 점입니다. 버튼이 그저 임의의 클래스명을 받고 아무런 변형도 없다면
00:06:13이 린터가 제안할 수 있는 내용이 없습니다. 따라서 디자인 시스템이 구축되어 있고
00:06:18실제 변형들을 사용하고 있어야 한다는 전제가 필요합니다. 솔직히 ShadCN UI를 쓰고 계시다면
00:06:22이미 갖춰진 상태이므로 대부분 문제없을 겁니다. 마지막 아쉬운 점은 현재 Oxlint와 ESLint에서만
00:06:27사용 가능하고 Biome 플러그인은 아직 없다는 것인데, GitHub에 이슈가 등록되어 있으니 조만간 지원되길 바랍니다.
00:06:31새로 나온 ShadCN Linter는 디자인 시스템을 더 잘 준수하도록 돕는 6가지 규칙으로 구성되어 있어,
00:06:36AI가 대부분의 코드를 작성하는 시대에 큰 도움이 됩니다. 이 린터가 여러분이 겪던 문제들을
00:06:41해결해줄지, 아니면 여전히 StarLex 같은 대안으로의 전환을 고려 중이신지
00:06:45하단 댓글로 알려주세요. 구독도 부탁드리며, 늘 그렇듯 다음 영상에서 뵙겠습니다.
커뮤니티 글
아직 글이 없습니다. 이 영상에 대한 첫 번째 글을 작성해 보세요!
이 영상에 대해 글쓰기