Web-component
웹컴포넌트에 대하여
2022-12-01Web Component ?
웹 컴포넌트는 웹 표준 기반의 재사용 가능한 클라이언트 사이드 컴포넌트이다. 원하는 코드의 기능을 캡슐화하여 재사용 가능한 커스텀 엘리먼트를 생성하고 웹 앱에서 활용할 수 있도록 해주는 다양한 기술들의 모음이다.
사용 이유
Vendor Lock-in
- 먼저, Vendor Lock-in의 대해 알아볼 필요가 있다. Vendor Lock-in 란, 특정 벤더의 독자적 기술에 크게 의존한 것으로, 다른 벤더가 제공하는 동종 제품 또는 서비스, 시스템 등으로 갈아타기 어려운 현상을 말한다. 쉽게 말해서, 최근들어서 자주 사용되는 React, Vue, Angular 등 Js 프레임워크를 기반으로 둔 컴포넌트를 활용했을 때 수 년이 지나고, 언어가 퇴보 되었을 때 코드 리팩토링하는 것은 굉장히 까다로운 작업이 될 것이다. 그래서 이러한 불편사항을 없애기 위해서 웹 표준 기술을 사용하면, 변화에 유연하게 대처할 수 있다.
- Web Component는 재사용 가능한 요소에 대하여, 강력한 캡슐화를 제공하며, custom element, shadow DOM, HTML template와 굉장히 친숙하다.
Web Component 의 전망
- 최근들어, 웹 컴포넌트를 많이 사용하는 추세로 가고있다.
- Chrome 브라우저에서 동작하는 웹 사이트의 15% 이상이 Custom Element를 사용하는 것으로 나타났다.
실제 사용한, React의 컴포넌트
하단의 이미지는, 스마트케어 업무 중 React 기반의 컴포넌트 HTML 을 작성하여, 업무를 수행한 기록이다. 우측 이미지와 같이 Challenge 폴더 안에 Componets폴더가 존재하고, 그와 같은 위치에 Challenge 및 각종 Challenge 등 과 같은 컨테이너(Container)가 존재하는 것을 볼 수 가 있다. 기본적으로 컨테이너에서 필요한 컴포넌트를 불러와 사용한다.
먼저 컴포넌트를 활용하기 위해서는, 기존에 되어있는 디자인을 유심히 볼 필요가 있다. 재 사용을 할 수 있는 것들부터 찾아본 다음, 그것을 직관적인 이름을 가진 컴포넌트로 만들면 된다. 하단의 이미지는, 실제 업무 수행과정 중 Challenge 메인 디자인 시안이다. 이 곳에서 나는 뒷 배경이면서도 모든 element를 담을 수 있는 container인 Wrapper와, 하단의 Card Layout 등 과 같이 컴포넌트로 담았다.
-
Challenge Componets
-
먼저 실제 사용한 Challenge 컨테이너(Container)의 코드이다. 아래와 같이 크게
<Wrapper> <Header> <MainMenu> <Container> <Layout><CouponLayout />등 세부적으로 컴포넌트를 생성했고, props를 통해서 실제 컴포넌트의 필요한 데이터들을 보내주며 코드를 작성했다. 앞서 작성한 것과 같이 React, Vue, Angular의 프레임워크를 기반으로 한 것들은 해당 언어의 문법이나 규칙 등을 알아야만 활용 할 수 있다는 단점이 존재한다.const ChallengePage = () => { const [isTabnavOn, setIsTabnavOn] = useState(false); const [isMenuType, setMenuType] = useState("benefit"); const [hasList, setHasList] = useState(true); return ( <React.Fragment> <Wrapper> <Header title="케어존" isTabnavOn={isTabnavOn} > <MainMenu MenuType={setMenuType} isMenuType={isMenuType} /> </Header> <Container> { isMenuType === "benefit" ? <> <Layout hasList={false} contentTitle="혜택 모아보기" cont="12" imgNum="1" text="2022.10.01 ~ 2024.10.01" personnel="1,234" type3={true} /> </> : isMenuType === "coupon" ? <> <CouponLayout /> </> : null } </Container> </Wrapper> </React.Fragment> ) }const Wrapper = ({ seeAllTruth, badgesTruth, detailsTruth, clearTruth, readTruth, children }) => { return ( <> <div className={cn({ [ChallengeCSS.Wrapper]: true, [ChallengeCSS.seeAll]: seeAllTruth, [ChallengeCSS.badges]: badgesTruth, [ChallengeCSS.details]: detailsTruth, [ChallengeCSS.clear]: clearTruth, [ChallengeCSS.read]: readTruth, })} > {children} </div> </> ) } -
Web Componets
웹 컴포넌트는 다른 프레임워크 언어와 쓰임새나 사용방법은 같지만, 작성하는 방법 등 차이가 있다. 실제 기본 HTML과 Javascript를 기반으로 두었기 때문에 오히려 더 친숙할 수 있다. 웹 컴포넌트에는 3가지 구현방법이 존재하는데, 다음과 같으며 하단에서 각각 기능과 장점에 대하여 서술하겠다.
-
Custom Element
-
Shadow DOM
-
HTML Template
- Custom Element
-
HTML Element와 Javascript Class를 하나로 만들어 캡슐화하여 재사용 가능.
-
사용자 지정 태그를 작성 가능(원하는 클래스 네이밍 사용)
-
사용방법
class TestModal extends HTMLElement { constructor() { super(); } this.innerHTML = ` <div class="modal"> TEST Modal </div> ` } customElements.define('test-modal', TestModal);<test-modal></test-modal>사용규칙
- Custom Elements를 사용할 Class는 반드시 HTMLElement를 상속 받아야한다.
- Custom Elements에는 React와 비슷하게 생명주기가 존재한다.
customElements.define을 이용해서 Custom Elements를 만들 수 있다. 첫번째 인자는 태그의 이름을 적어주면 되고 두번째 인자는 해당 Class의 이름을 적으면 된다. 이때 태그의 이름엔 반드시-가 들어가야 한다. (구분과 상속의 이유)
생명주기
-
connectedCallback
-
disconnectedCallback
-
attributeChangedCallback
-
adoptedCallback
-
Shadow DOM
- HTML의
<video>,<input type="range">와 같은 내부에 요소가 포함된 태그이다. - DOM 트리를 일반 DOM 트리의 요소에 첨부가능하다.
- Shadow DOM 트리는 모든 요소에 첨부할 수 있는 Shadow 루트로 시작한다.
- HTML의
사용방법
<div id="shadow"></div>document.querySelector('#shadow').attachShadow({mode : 'open'}) // mode는 'open' 과 'closed'가 있다. document.querySelector('#shadow').shadowRoot.innerHTML = '<p>쉐도우 돔 설명입니다.</p>'사용규칙
- 노드와 같은 방식으로 Shadow DOM 노드에 영향을 줄 수 있다.
- Shadow DOM의 내부 코드는 외부에 영향을 줄 수 없으므로 캡슐화를 허용한다.
- Shadow DOM의 상세정보들은 개발자도구에서 셋팅을 필요로한다.
-
개발자도구 → Settings → Show user agent shadow DOM 체크
- HTML Template
- HTML
<template>요소는 페이지가 렌더링 되고나서 그려지지 않는다. - Javascript를 사용해 인스턴스를 생성할 수 있는 html 코드를 담을 방법을 제공한다.
- 이 요소는 전역 특성만 포함된다.
- HTML
사용방법
<template id="template"> <h3>제목</h3> <p>제목설명입니다.</p> </template> <div id="wrap"></div>let temp = document.querySelector('#template'); let target = document.querySelector('#wrap'); let newContent = document.importNode(temp.content,true); target.innerHTML = ''; target.appendChild(newContent); -