최근에 웹 컴포넌트라는 개념을 처음 듣고 관심이 생기게 되었다 😀
새로 알게 된 기술을 학습할 때 공식 문서를 참조하여 간단하게 작은 것이라도 만들어 보고자 하는 편인데, 더 좋은 방법은 기존에 진행했던 프로젝트를 발전시키는 데에 적용하는 것이라고 생각한다
최근에 진행한 프로젝트 중 게임을 같이 할 파티원들을 모집하는 'POT' 프로젝트를 리액트나 뷰와 같은 프레임워크 없이 진행하게 되었다.
문제는 멀티 페이지 애플리케이션이다 보니, 거의 모든 페이지에서 사용되는 헤더에 작성되는 html 코드가 중복되어 한 페이지에서 코드를 수정하게 된다면 다른 모든 페이지에서도 코드를 일일히 수정해줘야 한다는 것이다.
이를 재사용하기 쉽게 커스텀 태그로 변환하고, 관리하기 용이하게 리팩토링 해보고자 한다 🙂
재사용 가능한 커스텀 엘리먼트를 생성하고 웹 앱에서 활용할 수 있도록 해주는 다양한 기술들의 모음
세 가지 주요 기술들로 구성되며, 재사용을 원하는 어느 곳이든 코드 충돌에 대한 걱정이 없는 캡슐화된 기능을 갖춘 다용도의 커스텀 엘리먼트를 생성하기 위해 함께 사용될 수 있다.
// components/Header.js
import setHeader from '../utils/header';
class Header extends HTMLElement {
constructor() {
super();
this.innerHTML = `
<header class="header">
<div class="header__wrapper">
<h1>
<a class="header__logo-link" href="/">
<img class="header__logo" src="/images/logo.png" alt="logo">
</a>
</h1>
<nav class="header__nav">
<a class="header__nav-link" href="javascript:void(0);"><span class="header__nav-create-pot">POT 생성</span></a>
<span class="header__nav-link login-info"></span>
</nav>
</div>
</header> `;
}
connectedCallback() {
setHeader();
}
}
export default function defineMainHeader() {
customElements.define('main-header', Header);
}
커스텀 엘리먼트의 클래스 내에서 라이프사이클 콜백을 지정할 수 있다
static get observedAttributes() {
return ['something'];
}
정상적으로 렌더링되는 것을 확인할 수 있고, 더 이상 헤더를 고칠때마다 매번 모든 페이지의 헤더를 고치는 것이 아니라 컴포넌트 단위로 수정하여 재사용성, 관리의 용이성을 높였다
위의 실습을 통해 커스텀 엘리먼트를 생성해보았다
그렇다면 스타일까지 모두 지정해 컴포넌트만으로 의미가 있는 하나의 모듈처럼 사용할 수는 없을까?
결론은 "있다"
쉬운 방법으로는 위의 예시에 innerHTML 내부에 <style>
태그를 사용해서 그 안에 스타일을 지정해주면 제대로 동작한다.
하지만 css는 전역적으로 적용된다는 점 때문에 컴포넌트가 여러개 생기고 각각 스타일을 지정하다보면 충돌이 발생할 수도 있다
이를 Shadow DOM을 통해 해결할 수 있다
Shadow DOM은 결코 새로운 것이 아니다. 흔히들 알고 있는 <video>
태그나 <input type="range" />
는 Shadow DOM 내부에 요소들이 포함되어 있다.
Shadow DOM을 사용하면 숨겨진 DOM 트리를 일반 DOM 트리의 요소에 첨부할 수 있다
Shadow DOM 트리는 모든 요소에 첨부할 수 있는 shadow 루트로 시작한다
const shadow = this.attachShadow({mode: 'open'});
위 사진과 같이 shadow-root가 연결되어 하위에 요소를 첨부할 수 있다
다만, 기존 프로젝트 스타일 적용 방식이 Sass를 컴파일 해서 적용하는 방식으로 사용했으므로 일관성을 위해 Shadow DOM은 학습 차원에서 마무리 지었다
웹 컴포넌트를 학습하며 html, css, js가 모두 한 파일에 있는 것이 Vue.js의 .vue 파일과 상당히 유사하다는 느낌을 받았다
Vue나 React 같은 라이브러리나 프레임워크가 없던 시절에는 웹 컴포넌트를 사용했다고 한다
실제로 github에서는 프레임워크 없이 웹 컴포넌트를 사용해 사이트를 구축했다
특정 라이브러리나 프레임워크는 영원할 수 없고, 웹 컴포넌트는 표준 기술이기에 웹 컴포넌트를 사용해보는 것은 의미있는 일이라고 생각한다.
프로젝트가 이미 마무리된 시점에서 억지로 웹 컴포넌트를 적용하려고 하니 쉽지 않았고, 그렇기에 제한되는 조건이 많아서 아쉬움이 남는다. 하지만 이번 경험을 발판 삼아 다음에 다시 사용해 볼 기회가 생긴다면 더 잘해볼 수 있을 것 같다고 느낀다❗️
reference
https://developer.mozilla.org/en-US/docs/Web/Web_Components
https://www.youtube.com/watch?v=RtvSgptpfnY&t=284s![](https://velog.velcdn.com/images%2Fjhyj0521%2Fpost%2F51f6b40e-6d5f-456c-8749-1ecb46f26d81%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-08%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%202.50.01.png)