본문 바로가기
자료수집/IT 기술분석

웹 컴포넌트는 왜 등장했을까?

by 3604 2023. 9. 15.
728x90

출처: 웹 컴포넌트는 왜 등장했을까? | 요즘IT (wishket.com)

내가 처음 배웠던 개발 언어는 자바스크립트다. 리액트(React)로 유튜브나 인스타그램 같은 인기 서비스를 클론 코딩하는 수업 광고를 보고 흥미가 생겨, 따라 만들어보면서 본격적인 개발 공부를 시작했다. 내가 프론트엔드 엔지니어로서 커리어를 막 시작했을 땐 웹과 리액트를 거의 동일한 것으로 인식하고 있었다. 그러나 웹을 좀 더 깊이 공부하면서 웹은 리액트도, 뷰도 아니라는 것을 알게 되었다.

 

현재 일하는 곳에서는 뷰(Vue)를 사용하고 있는데, 뷰나 리액트는 웹을 만들기 위한 도구일 뿐이라는 것이다. 그렇다면 바닐라 자바스크립트만으로도 웹을 만들 수 있을까? 정답은 ‘Yes’다. 웹에서 제공하는 API들을 통해 바닐라 자바스크립트 문법으로도 HTML 태그들을 제어할 수 있기 때문이다.

 

Web API를 활용하면 DOM 트리에 접근하여 수정하고 삭제할 수 있음은 물론이고, 리액트나 뷰처럼 컴포넌트를 만드는 것도 가능하다. 이를 웹 컴포넌트라고 한다. 이번 글에서는 웹 컴포넌트 개념과 도입 배경에 대해 살펴보고자 한다.

컴포넌트와 웹 컴포넌트

컴포넌트란 재사용 가능하고 캡슐화되어있는 클래스 또는 그 클래스를 기반으로 생성되는 각각의 인스턴스를 말한다. 컴포넌트 개념이 처음 나타난 시기는 1990년대까지 거슬러올라간다. 재사용성에 초점을 맞춘 컴포넌트 기반 아키텍처(CBA)라는 설계 방법이 소프트웨어 엔지니어들 사이에서 활발히 논의되기 시작했다. CBA의 핵심 원칙은 모듈성, 재사용성, 독립성이다.

 

  • 모듈성: 소프트웨어는 독립적인 컴포넌트로 나뉘며, 각 컴포넌트는 특정 기능을 수행하는 모듈 역할을 한다.
  • 재사용성: 컴포넌트는 다양한 애플리케이션에서 재사용될 수 있어야 한다.
  • 독립성: 컴포넌트는 독립적으로 운영될 수 있으며, 다른 컴포넌트에 최대한 의존하지 않아야 한다.

 

웹 개발에서는 2010년대가 되어서야 재사용성과 모듈화에 대한 고민이 시작됐다. 초기 웹 개발 생태계에서는 큰 로직을 다룰 일이 없었기 때문이다. 초기 웹의 목적은 주로 정적인 문서를 공유하는 것이었다. 1990년대 초 팀 버너스 리가 웹을 발명했을 때, 그의 목표는 연구원들이 연구 결과와 문서를 공유하도록 하는 것이었고, 이런 간단한 목적에는 컴포넌트화된 아키텍처의 필요성이 뚜렷하지 않았다.

 

초기의 웹 기술, 특히 HTML은 내용의 구조와 의미를 표현하는 데 초점이 맞춰져 있었고, 모든 콘텐츠는 정적으로 처리되었다. 이후 점차 사용자와 상호작용하는 UI/UX에 대한 수요가 생기면서, 자바스크립트와 AJAX 등의 기술이 빠르게 발전했고 웹 애플리케이션의 복잡성이 증가했다.

 

이러한 복잡성을 관리하기 위해 웹에도 컴포넌트 기반 접근법을 도입해야 한다는 필요성이 제기되었다. 웹 엔지니어들은 UI를 작고 재사용 가능한 컴포넌트 단위로 나누어 개발하는 접근법을 논의하기 시작했다. 그리고 2011년 웹 컴포넌트가 등장했다. 2013년 W3C에 의해 표준 웹 API가 만들어지면서 모던 브라우저들은 이 API들을 제공하게 되었다.

 

리액트와 뷰도 이 즈음에 만들어졌다. 컴포넌트 기반의 메서드와 함께 렌더링 퍼포먼스와 빌드 퍼포먼스를 높이기 위한 편리한 기능들을 추가했다. 기본적으로 컴포넌트의 목적과 기능은 프레임워크와 웹 컴포넌트 모두 동일하다.

 

 

웹 컴포넌트 API

바닐라 자바스크립트로 웹을 만든다는 것은 웹 API와 HTML 태그를 사용한다는 것을 의미한다. 모던 웹 API에는 HTML 태그들을 다룰 수 있는 여러 메서드들이 제공된다. HTML 태그들의 묶음을 재사용 가능하고 캡슐화된 덩어리, 즉 ‘웹 컴포넌트’로 만들 수 있는 API들도 있는데, 이 HTML 덩어리 또는 API 들의 모음을 웹 컴포넌트 API(Web Component API)라고 부른다. 이를 활용하면 화면에 그려질 DOM 트리의 조각들을 레고 블록처럼 조립할 수 있다. 리액트와 뷰의 컴포넌트 개념과도 유사하다.

 

자바스크립트 문법에도 클래스가 존재한다. 웹 컴포넌트에는 이 클래스가 활용된다. class를 만들면 웹 컴포넌트로 선언할 수 있다. 웹 컴포넌트를 만들기 위한 대표적인 API에는 대표적으로 다음과 같은 스펙들이 있다.

 

  • Custom elements 생성
  • Shadow DOM 등록을 통한 캡슐화
  • HTML templates와 Slot을 통한 컴포넌트 재사용
  • 라이프사이클

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Component Example</title>
</head>
<body>
    <!-- 웹 컴포넌트 사용 예시 -->
    <my-web-component>
        <span>This is a slotted content!</span>
    </my-web-component>

    <script>
        class MyWebComponent extends HTMLElement {
            constructor() {
                super();
                this.attachShadow({ mode: 'open' });

                // Define the template
                const template = document.createElement('template');
                template.innerHTML = `
                    <style>
                        p {
                            color: blue;
                            font-size: 20px;
                        }
                        slot::slotted(span) {
                            font-weight: bold;
                        }
                    </style>
                    <p>Hello from My Web Component! <slot></slot></p>
                `;

                this.shadowRoot.appendChild(template.content.cloneNode(true));
            }
        }

        // Register the web component
        customElements.define('my-web-component', MyWebComponent);
    </script>
</body>
</html>
Plaintext

 

먼저 HTML에서 사용될 웹 컴포넌트 이름을 정의한다. 이때 컴포넌트 이름에는 반드시 ‘-’ 가 포함되어야 한다. 그리고 HTMLElement 클래스를 확장하여 웹 컴포넌트의 기능을 정의한 후에 customElements.define() API를 사용하여 웹 컴포넌트를 정의하고 브라우저에 등록한다.

 

커스텀 컴포넌트를 shadow DOM으로 등록한다는 것은 캡슐화하는 것을 의미한다. 커스텀 컴포넌트로 사용할 클래스를 정의할 때 생성자 안에서 attachShadow() API를 호출하면, 해당 커스텀 컴포넌트는 shadow DOM이 된다. 캡슐화의 가장 직관적인 장점은 내부에서 선언한 style이 격리된다는 점이다. 뷰에서 style 태그의 scoped 속성으로 style을 격리하는 것과 유사하다.

 

HTML templates와 slot을 사용하는 방식 역시 뷰를 사용해 본 사람이라면 비슷하다고 느낄 것이다. 커스텀 컴포넌트로 감싼 내부에 내용을 적으면, 그 내용은 커스텀 컴포넌트 클래스에서 선언한 템플릿 안에서 렌더된다.

 

또한 웹 컴포넌트 API에는 생명주기 콜백도 존재한다. 웹의 중요한 부분이 렌더링 성능인 만큼, 생명주기를 관리할 수 있는 것은 매우 유용하다.

 

  • connectedCallback : 커스텀 컴포넌트가 DOM에 추가될 때 호출
  • disconnectedCallback : 커스텀 컴포넌트가 DOM에서 해제될 때 호출
  • adoptedCallback : 커스텀 컴포넌트가 새로운 DOM으로 이동할 때 호출
  • attributeChangedCallback : 커스텀 컴포넌트 속성에 변경이 생겼을 때 호출

 

 

뷰, 리액트 컴포넌트와 다른 점은?

웹 컴포넌트 API의 기본적인 작동원리와 사용방법은 여느 프레임워크의 컴포넌트와 다르지 않다. 기본적인 라이프 사이클도 제공되고, 만약 전역 상태 관리를 원한다면 mobx나 redux를 붙일 수 있기에 사용성 면에서 크게 불편한 부분은 없을 것 같다. 다만 커뮤니티가 작고, 필요한 개발 환경 설정을 직접 일일이 해야 하는 부분이 까다로울 수는 있다.

 

개인적으로 큰 프로젝트에서 웹 컴포넌트 API를 사용해 본 경험이 아직 없어서 성능에 관해서는 단정하기 어렵다. virtual DOM의 변경사항을 비교하는 diffing 없이 곧바로 DOM이 변경된다는 것이 대개의 경우 더 좋은 성능을 보일 것 같다. 하지만 변경사항이 많은 경우 뷰나 리액트의 diffing을 비롯해, 생태계에서 논의를 거쳐 적용된 퍼포먼스 개선 기능에 의해 훨씬 더 좋은 성능을 보일 것 같다.

 

그리고 웹 컴포넌트는 뷰와 리액트와 완전히 분리해서 사용해야 하는 기술이 아니다. 만약 원한다면 혼용해 사용할 수 있다.

컴포넌트의 개념을 알고 사용하자

컴포넌트 기반의 접근법은 그 자체로 혁신적인 변화를 웹 개발 분야에 가져왔다. 이전에는 웹 페이지나 애플리케이션을 개발할 때 각 화면이나 기능마다 코드를 처음부터 끝까지 작성해야 했다. 그 결과 코드 중복이 많아지고 유지 보수가 어려워지는 문제가 발생했다. 하지만 컴포넌트화된 아키텍처를 도입함으로써, 개발자는 일련의 기능이나 UI 요소를 재사용 가능한 블록으로 만들 수 있게 되었다. 이 블록들은 다양한 상황에서 재활용되면서 코드의 효율성과 가독성을 크게 향상시켰다.

 

또한 웹 애플리케이션의 규모가 커짐에 따라 그 복잡성도 함께 증가했다. 사용자의 기대치도 높아져, 웹 애플리케이션은 더 빠른 로딩 시간, 부드러운 상호작용, 더 나은 사용자 경험을 제공해야 했다. 컴포넌트 기반 아키텍처는 이러한 요구 사항에 부응하기 위한 해결책 중 하나로 자리 잡았다. 웹 컴포넌트 API는 이러한 수요 속에서 등장했다.

 

그리고 리액트와 뷰는 컴포넌트의 재사용성을 넘어, 선언적 UI, 가상 DOM, 반응형 프로그래밍 등과 같은 다양한 기능과 최적화 기법을 제공하여 개발자들이 더 나은 웹 애플리케이션을 더 빠르게 제작할 수 있게 도와주었다.

 

이번에 컴포넌트 개념의 히스토리를 찾아보면서, 그동안 웹 프레임워크를 다루면서 당연하게 여겼던 컴포넌트가 사실은 많은 고민의 산물이라는 것을 알게 되었다. 그리고 웹 컴포넌트라는 것이 필요하지 않을 정도로 단순한 웹의 시대가 존재했다는 것, 사람들이 웹에 머무는 시간이 길어지고 상호작용이 많아지면서 복잡하고 방대한 웹을 유지 보수해야 하는 필요에 의해 웹 컴포넌트가 생겨났다는 사실도 신선하게 느껴졌다.

 

웹 컴포넌트가 크로스 프레임워크 기술이라는 장점 때문에 기존 프레임워크들을 대체할 것이라는 의견도 있다. 그러나 프레임워크가 제공하는 편리함을 사람들이 쉽게 포기할 것 같진 않다. 프론트엔드 개발자로서 한 번쯤 웹 컴포넌트 API를 공부해 보면, 사용하는 프레임워크에 대한 이해도를 높이는 데 도움이 될 것이다.

참고:

 Vue.js는 프레임워크(The Progressive JavaScript Framework), React.js는 라이브러리(사용자 인터페이스를 만들기 위한 JavaScript 라이브러리)

 

728x90
반응형