개요 컴포넌트를 만들다 보면 필연적으로 간격을 어디에 줄 것인가에 대한 고민에 빠지게 된다. 예를 들어, 리스트에 들어갈 `UserCard`라는 컴포넌트를 만든다고 가정해보자. 리스트 아이템 사이에는 20px의 간격이 필요하다. 이때 가장 쉬운 방법은 `UserCard` 자체에 `margin-bottom: 20px`을 주는 것이다. "어차피 이 카드는 리스트에서만 쓰니까, 알아서 간격을 가지고 있으면 편하잖아?" 하지만 프로젝트가 커지고 `UserCard`를 다른 곳(가로 스크롤 뷰, 모달 내부, 그리드 레이아웃 등등)에서 재사용하려고 할 때, 내부에 심어둔 이 margin은 굉장히 거슬리는 무언가가 돼버린다. ▼ 나는 "자식 컴포넌트는 패딩이나 마진 같은 외부 간격에 대해 전혀 몰라야 한다"는 ..
개요 기획서나 디자인 시안을 보다 보면 정말 흔하게 등장하는 UI가 있다. 바로 긴 텍스트 줄이기다. 보통은 3줄 정도 보여주고, 넘치면 말줄임표(...) 처리를 한다. 여기까지는 CSS의 -webkit-line-clamp 속성만 쓰면 3초 만에 해결된다. 하지만 요구사항이 아래와 같다면 이야기가 달라진다. "3줄 넘어가면 말줄임표 하고, 그 '바로 옆'에 더보기 텍스트 버튼을 넣어주세요. 버튼 누르면 펼쳐지고요." 단순히 ...으로 끝나는 게 아니라, 인터랙션이 가능한 버튼이 텍스트 흐름에 자연스럽게 붙어야 한다. '그냥 position: absolute로 띄우면 되는 거 아닌가?' 싶지만, 막상 해보면 생각보다 까다로운 문제들이 발생한다. 오늘은 이 '더보기' 버튼을 자연스럽게 넣기 위해 삽질했던..
개요 유지보수를 하면서 이전에 작성된 코드를 보는데 `{...props}` 문법이 정말 많이 보였다. 리액트의 문법들에 대해 다 알지 못했기에 무슨 이런 해괴한 문법이 있나... 하면서 찾아보니 꽤나 유용한 문법이었다. 처음 봤을 때는 솔직히 조금 불편했다. 명시적으로 어떤게 있는 지 모르니 말이다... 그러면서 이건 아무래도 안티 패턴인거 같다는 생각이 들었고, 커뮤니티랑 글들을 찾아보니 내 생각이 맞았다. 얼핏 보면 코드도 간결하고, 고수처럼 코딩하는 것 처럼 보인다.// 이렇게 간단하게 props를 넘길 수 있다니!function ParentComponent() { const userProps = { name: '노근', age: 25, job: 'Developer' }; return ;} ..
개요 React로 폼을 개발하다가 꽤나 당황스러운 버그가 나타났다. 새로고침(F5)을 누르면 분명 State는 초기화되는데, Input에는 이전에 입력했던 값이 그대로 남아있는 것이다. 더 황당한 건 입력 값은 보이는데 Preview 영역에는 아무것도 표시되지 않는다는 점이었다. 처음에는 '내가 State 관리를 잘못한 건가?' 싶어서 코드를 여러 번 확인했다. 하지만 크롬에서는 문제없이 잘 작동했다. 문제는 Firefox와 Firefox 기반 브라우저(Floorp, Librewolf 등)에서만 발생했다. 문제 상황구체적인 상황은 이랬다. ▼사용자가 폼에 데이터를 입력입력한 데이터가 Preview 영역에 실시간으로 표시됨새로고침(F5) 실행React State는 정상적으로 초기화됨그런데 Input/Te..
개요 React 개발을 시작한 지 얼마 안 됐을 때, 나의 컴포넌트는 대충 이런 모습이었다. ▼ ... 솔직하게 말하면 지금도 종종 저러고 있는거 같다. 끝없이 중첩된 `div`들... 당시에는 어떤 문제가 생기는지도 모르고 굉장히 편리하네라고 생각했지만, 몇 개월 후 그 코드를 다시 열어봤을 때 이게 뭐하는 `div`였더라?라는 질문만 남았다. 여러 프로젝트를 경험하며 왜 모든 걸 `div`로 해결하면 안 되는가?라는 질문에 대한 답을 찾아가게 되었다. 그래서 이번 글에서는 단순히 시맨틱 HTML을 써라는 교과서적인 이야기가 아니라, 실제로 `div`를 남발했을 때 어떤 고통이 기다리고 있는지를 내 경험과 함께 풀어보려고 한다. 그전에... 왜 div만 쓰게 될까?솔직..
개요 국제화(i18n)를 구현하다 보면 번역 파일을 어떻게 관리할 것인가?라는 질문을 마주하게 된다. 처음에는 하나의 거대한 JSON 파일에 모든 번역을 때려넣으면 될 것 같지만, 프로젝트가 조금만 커져도 수천 개의 키가 뒤엉키게 된다. 그래서 이번 글에서는 국제화 파일을 페이지별로 분할해서 관리하되, 빌드 시점에 자동으로 병합하는 방식을 소개하려고 한다. 단순히 이렇게 하면 된다고 결론부터 내리기보다, 왜 이런 접근이 필요했는지, 그리고 실제로 어떻게 구현했는지의 흐름을 따라가보자. 문제파일 분할의 필요성국제화 파일을 단일 파일로 관리하면 처음에는 간단해 보인다. en.json 하나, ko.json 하나, 끝. 더 필요하면 es.json 혹은 ja.json 정도. 하지만 프로젝트가 커지면서 문제가 ..
문제 상황styled-component에서 tailwind-css로 마이그레이션을 하기 위해 tailwind-css를 아래와 같이 설치했는데, ▼npm install -D tailwindcss postcss autoprefixernpx tailwindcss init -p 아래와 같은 문제가 발생했다. ▼npm error could not determine executable to runnpm error A complete log of this run can be found in: [필자의로그].log 해결문제를 해결하기 위해 구글링을 해본 결과, Reddit에서 해결 방법을 구할 수 있었다. ▼ From the reactjs community on RedditExplore this post and mo..
개요 Flutter로 개발하다 위젯 관리에 대한 이야기가 나왔다. "위젯들을 어떻게 체계적으로 관리할 수 있을까? 프론트 내부 QA를 빠르게 하는 방법이 없을까?" 하는 의문들도 같이 나왔다. 프로젝트가 커지면서 버튼 하나만 해도 여러 variants가 생기고, 각각 다른 상태들을 확인해야 하는 상황이 생긴다. 그런데 매번 앱을 실행해서 특정 화면으로 가서 버튼을 확인하는 건 꽤나 비효율적이다. 더 나아가 디자이너나 기획자가 "이 버튼의 disabled 상태는 어떻게 보이는 거죠?"라고 물어보면 설명하기가 난감하다. 직접 켜서 보여줘야하는 부분이 상당히 번거롭다. 이런 문제를 해결하기 위해 Storybook의 Flutter 버전이라고 할 수 있는 WidgetBook을 프로젝트에 도입해봤다. 결론부터 ..
HI-ARC intra.hiarc-official.com 개요대규모 웹 프로젝트를 진행하다 보면 누구나 한 번쯤 이런 고민에 빠진다. "서비스가 여러 개일 때, 프로젝트 구조는 어떻게 나눠야 할까?" 특히 여러 명의 개발자가 동시에 작업하는 협업 환경이라면, 구조적 통일성과 생산성, 유지보수 효율성은 무시할 수 없는 요소다. 이때 흔히 등장하는 해답이 바로 모노레포(Monorepo) 구조다. 한 레포에서 여러 앱을 관리하고, 공통 UI와 유틸리티를 공유하고, 통합된 빌드 환경과 테스트, 린트를 적용할 수 있다. 한 번에 관리되는 코드베이스라는 것은 꽤나 매력적으로 다가온다. (필자는 플러터를 했을 때 부터 느낀 거지만, 한 번에 많은 것이 관리되는 코드베이스에 매력을 느끼는 것 같다.) 이 글에서는 ..
개요 클린 아키텍처를 웹 프로젝트에 도입해보려고 했다. Flutter에서 꽤 괜찮은 경험이었기에 React 기반의 웹 프로젝트에도 자연스럽게 잘 들어맞을 것이라고 생각했다. 한동안 웹을 모바일 앱과 같이 만드는 SPA방식이 대세였기에 구조적으로 비슷하기에 적용이 잘 되지 않을까 싶었다. 하지만 막상 프로젝트에 적용해보니, "이게 과연 웹에 맞는 구조인가?" 라는 의문이 강하게 들었다. 디렉토리는 복잡해지고, 코드 응집도는 떨어지고, 생산성은 낮아졌다. 무엇보다 초기 프로젝트 세팅에 너무나도 많은 시간이 들어가게 된다. 글로도 기록을 남겼었는데, 처음에 도입을 했을 때는 꽤나 좋았다. 하지만 시간이 지날 수록 의문이 많이 들었다. ▼ [Next.js][Develop] Next.js 클린 아키텍처 적용기..