이형주 / 디자인 시스템
hyungju-lee.com
사용기술 - LitJS, TypeScript, Web Components, Vite, pnpm
LitJS를 선택한 이유
Web Components를 사용하여 개발할 때 보다 더 쉽게 개발할 수 있게 해줌
TypeScript를 사용한 이유
빌드 결과물로 *.d.ts 파일도 내보내게하기 위함 (vite-plugin-dts 사용)
다른 곳에서 가져다 사용할 때 타입추론 가능
Web Components를 사용한 이유
프레임워크 상관없이 공통 컴포넌트를 개발하기 위해
Vite를 사용한 이유
개인적으로 설정이 webpack 보다 쉬워서
pnpm을 사용한 이유
모노레포 관리 툴 중 의존성 표시가 명확함
개발 과정
LitJS, TypeScript 기반 umd, react v18(esm), vue v2(esm), vue v3(esm) + pnpm 프로젝트 각각 생성 (모노레포 환경 구축)
LitJS를 활용하여 공통 컴포넌트 개발
react v18, vue v2, vue v3 환경에서 사용할 수 있도록 래핑처리
react v18 / createComponent 함수 활용
vue v2 / Vue.extend 활용
vue v3 / defineComponent 활용
위 함수들을 활용해 웹 컴포넌트를 래핑하여 빌드
일반 html, 즉, JSP, WoowahanJS 환경에는 umd로 빌드된걸 활용하여 공통 컴포넌트 적용
Vue, React 프로젝트에는 esm 형식으로 빌드된걸 활용하여 공통 컴포넌트 적용
개발할 때 반드시 지키고자 했던 부분
Headless UI 기법
쉽게 말해 공통 컴포넌트엔 로직만 존재, 기본 스타일조차 존재하지 않음.
공통 컴포넌트를 사용할 때 자유도를 높이기위함.
실제 사용 예시
특정 페이지에 form 관련 요소들이 있는데, 해당 요소들의 값이 사용자 입력에의해 변경되면 페이지 이탈시 수정된 값이 있음을 알리는 팝업을 띄워야하는 기능을 추가해야됨
해당 페이지의 GNB를 포함한 껍데기는 JSP로, 내부 요소들은 WoowahanJS에 의해 개발되어있던 상황 (WoowahanJS로 개발되어있는 부분에도 링크 이동 버튼들이 존재)
그리고 위 기능을 적용해야되는 다른 페이지는 GNB를 포함한 껍데기는 JSP, 내부 영역은 React로 개발
위에서 개발한 공통 컴포넌트를 통해 쉽게 적용
// JSP 환경
// 아래와 같이 wc-changed 웹 컴포넌트로 기존 form 관련 요소를 감싸기만하면, 최초값과 a태그를 클릭했을 때의 값을 비교해 값이 달라졌는지 여부를 체크
// 웹 컴포넌트 내부에 로직이 존재하기 때문에 아래와 같이 작성만해도 원하는 기능이 구현됨
// 물론 자유도를 더 높이려면 커스텀 이벤트를 이밋하는 방식으로 처리해도됨 (추후에 이런 방식으로 수정함)
<script src="wc-ui.js"></script>
<wc-changed-anchor>
<a href="###">링크</a>
</wc-changed-anchor>
<wc-changed>
<input type="text" />
</wc-changed>
// React 환경
// 아래와 같이 wc-changed 웹 컴포넌트로 기존 form 관련 요소를 감싸기만하면, 최초값과 a태그를 클릭했을 때의 값을 비교해 값이 달라졌는지 여부를 체크
// 웹 컴포넌트 내부에 로직이 존재하기 때문에 아래와 같이 작성만해도 원하는 기능이 구현됨
// 물론 자유도를 더 높이려면 커스텀 이벤트를 이밋하는 방식으로 처리해도됨 (추후에 이런 방식으로 수정함)
import WcChangedAnchor from 'common-ui/react';
import WcChanged from 'common-ui/react';
<WcChangedAnchor>
<Link href="###">링크</Link>
</WcChangedAnchor>
<WcChanged>
<input type="text" />
</WcChanged>
// Vue 환경
// 아래와 같이 wc-changed 웹 컴포넌트로 기존 form 관련 요소를 감싸기만하면, 최초값과 a태그를 클릭했을 때의 값을 비교해 값이 달라졌는지 여부를 체크
// 웹 컴포넌트 내부에 로직이 존재하기 때문에 아래와 같이 작성만해도 원하는 기능이 구현됨
// 물론 자유도를 더 높이려면 커스텀 이벤트를 이밋하는 방식으로 처리해도됨 (추후에 이런 방식으로 수정함)
import WcChangedAnchor from 'common-ui/vue';
import WcChanged from 'common-ui/vue';
<WcChangedAnchor>
<Link href="###">링크</Link>
</WcChangedAnchor>
<WcChanged>
<input type="text" />
</WcChanged>
위와 같이 하나의 웹 컴포넌트를 만들고, 해당 컴포넌트를 각 프레임워크에 맞게 래핑처리를 한 후 빌드한 후에, 각 환경에서 적절한 코드를 가져다 사용.
위와 같이하면 각 프레임워크에 맞게 공통 컴포넌트를 개발할 필요가 없게됨.
느낀점 및 한계
위 과정을 통해 느낀점은 다음과 같음
여러 기술스팩이 섞여있는 프로젝트가 있다면, 웬만하면 기술 스펙을 하나로 통일하기위한 노력을 하는 것이 좋다는 것을 느낌.
그 이유는 코드 복잡도가 증가하기 때문.
하지만 시간과 인력이 없을 경우, 프로젝트 및 서비스를 여러 기술로 개발해놓은 상태라면, 그리고 일단 주어진 기간 안에 반드시 무슨 수를 써서라도 기능을 구현해야되는 경우, 프레임워크에 구애받지않는 공통 컴포넌트는 좋은 차선책이 될 수 있다고 생각함.
1번과 반대로 한편으론 코드 복잡도를 줄일 수 있다는걸 느낌
swiper.js를 사용할 때, react, vue, svelte 환경에서 적용하는 코드 방식이 달라짐.
하지만 Web Components를 활용해서 swiper.js를 추상화해놓으면 어떤 프레임워크에서도 적용방식이 똑같아짐.
또한 각 프로젝트마다 swiperjs를 설치할 필요도없어 버전관리가 더 쉬워짐. (공통 컴포넌트에서 하면되기 때문)
이는 정말 큰 장점이라고 생각함.
개인 블로그
https://hyungju-lee.com/common-ui/
위 개발 내용을 정말 간단하게 정리한 개인 페이지
다음 내용이 궁금하다면?
이미 회원이신가요?
2024년 7월 27일 오후 1:40
바이브 코딩을 여러가지 카테고리에 적용해보고 있는데, 머신러닝쪽은 압도적으로 좋네요. 진짜 코드를 안 봐도 될 정도임.
심지어 머신러닝 연구 작업 특성상 코드를 안봐도 되니까 실험하는게 겁나 재밌어짐. 미쳤음. GPU 무한대로 준다는 말에 혹한다는 것이 완전 이해가 됨.
어떤 서비스가 버그를 가진채로 출시되었고, 사용자들이 그 버그를 전제로 기능을 사용하고 있다면, 그리고 그 위로 너무 많은 새로운 기능들이 쌓여있다면 그건 버그가 아니라 스펙(기능)이라는, 언젠가부터 들었던 업계의 유명한 블랙 유머다.
... 더 보기