SW/JavaScript

웹 컴포넌트: 모든 것을 알아야 합니다

얇은생각 2024. 7. 15. 23:30
반응형

웹 컴포넌트는 HTML, CSS, JavaScript와 같은 표준화된 기술 요소들로 구성된 구조로, 다른 웹사이트나 애플리케이션에서 사용할 수 있도록 해주는 요소 집합입니다. 이 글에서는 웹 컴포넌트의 개념, 필요성, 주요 사양, 호환성, 그리고 도전 과제 등 모든 것을 다룰 것입니다.

 

웹 컴포넌트: 모든 것을 알아야 합니다

 

웹 컴포넌트란 무엇인가?

웹 컴포넌트는 HTML, CSS, JavaScript와 같은 표준화된 기술 요소들로 구성된 구조로, 다른 웹사이트나 애플리케이션에서 사용할 수 있도록 해주는 요소 집합입니다. 이러한 기술은 기능과 외관 모두에서 맞춤형 요소를 생성할 수 있게 합니다. 웹 컴포넌트의 강점 중 하나는 프레임워크에 종속되지 않는다는 점으로, 어떤 자바스크립트 프레임워크에서도 사용할 수 있습니다. 이를 통해 여러 플랫폼과 기술을 사용하면서도 공유 컴포넌트 라이브러리를 가질 수 있습니다. 이는 브랜드 이미지를 통일하고 유지하는 데 매우 유용합니다.

 

왜 웹 컴포넌트를 사용해야 하는가?

대부분의 웹 개발은 Angular, Vue, React JS와 같은 자바스크립트 프레임워크 하에서 이루어집니다. 이러한 프레임워크와 라이브러리는 개발자에게 개발을 더 빠르고 신뢰성 있게 해주는 도구를 제공합니다. 그러나 문제는 여러 프로젝트에서 동일한 컴포넌트를 사용하려 할 때 발생합니다. 각기 다른 프레임워크를 사용하기 때문에 해당 부분을 중복 코드로 작성해야 하며, 이는 유지보수에 어려움을 초래합니다. 웹 컴포넌트를 사용하면 HTML, CSS, JavaScript를 이용해 프레임워크나 라이브러리에 의존하지 않는 맞춤형 컴포넌트를 개발할 수 있습니다. , 한 번만 작성하면 모든 프로젝트에서 사용할 수 있습니다.

또한 회사가 강력한 기업 이미지를 가지고 있지만 다른 플랫폼이나 웹 도구를 사용하는 경우, 웹 컴포넌트를 사용하면 스타일을 통일하는 데 유용합니다. 디자이너가 회사 이미지에 맞는 컴포넌트를 만들고, 개발자는 이를 한 번만 구현하면 되기 때문에 통일된 스타일을 유지할 수 있습니다.

 

웹 컴포넌트 사양

웹 컴포넌트는 다음과 같은 네 가지 주요 사양에 기반합니다:

 

커스텀 엘리먼트

커스텀 엘리먼트는 새로운 HTML 태그를 만들 수 있는 API 세트입니다. 시각적 수준에서의 생성 방식과 동작을 정의할 수 있습니다. 커스텀 엘리먼트에는 두 가지 유형이 있습니다:

  1. 자율 커스텀 엘리먼트: 완전히 새로운 HTML 요소를 생성하는 데 사용됩니다.
  2. 커스텀된 내장 요소: 기존 HTML 요소나 다른 웹 컴포넌트를 확장하는 데 사용됩니다.

 

쉐도우 DOM

쉐도우 DOM API는 원래 DOM의 조각을 격리하여 더 큰 요소에 속하는 내부 요소를 숨길 수 있게 합니다. 내부 동작은 iframe과 유사하여 콘텐츠를 문서의 다른 부분과 격리하지만, 내부 콘텐츠에 대한 전체 제어를 유지합니다. 이를 통해 CSS JavaScript 코드가 다른 커스텀 엘리먼트로 유출되지 않도록 합니다.

ES 모듈

ES 모듈은 JavaScript ES6에 포함되어 있으며, 라이브러리의 일부 기능을 그룹화하고 다른 JavaScript 파일에서 재사용할 수 있게 합니다. 이는 표준화된 모듈 시스템을 제공하여 다양한 기능을 다른 파일에서 사용할 수 있게 합니다.

HTML 템플릿

HTML 템플릿은 재사용 가능한 HTML 코드 스니펫을 작성할 수 있게 합니다. 이러한 템플릿은 페이지 로드 시 즉시 렌더링되지 않으며, JavaScript를 사용하여 런타임에 메인 문서에 삽입할 수 있습니다. 템플릿이 문서에 삽입될 때 내부 리소스가 실행되므로, 성능이 보장됩니다.

호환성

웹 컴포넌트의 호환성은 매우 넓습니다. Chrome, Firefox, Edge와 같은 모든 Evergreen 브라우저에서 문제가 없이 지원됩니다. 그러나 Internet Explorer Safari와 같은 브라우저에서는 호환성에 예외가 있습니다. Internet Explorer Microsoft의 종료로 인해 2023 2 14일부터 접근이 차단되었습니다. Safari의 경우, 자율 커스텀 엘리먼트는 100% 호환되지만, 쉐도우 DOM과 커스텀된 내장 요소는 아직 구현되지 않았습니다.

웹 컴포넌트의 도전 과제

웹 컴포넌트는 구현 가치가 있는 위치를 찾고 다양한 도전 과제를 극복하기 위해 많은 발전을 이뤘습니다. 그러나 여전히 개선의 여지가 있습니다.

일반 스타일과의 통합

웹 컴포넌트가 직면한 도전 과제 중 하나는 애플리케이션의 일반 스타일을 덮어쓰는 방법입니다. 이를 해결하기 위해 몇 가지 옵션이 있습니다:

  1. 쉐도우 DOM 사용하지 않기: 스타일을 커스텀 엘리먼트에 직접 추가할 수 있습니다. 하지만 이는 코드가 우연히 또는 악의적으로 변경될 위험이 있습니다.
  2. 클래스 사용: 이 클래스는 쉐도우 DOM의 커스텀 엘리먼트를 선택하고 특정 방식으로 스타일링할 수 있게 합니다.
  3. CSS 커스텀 속성 사용: 커스텀 속성 또는 변수는 웹 컴포넌트에서 계단식으로 연결되어, 엘리먼트가 변수를 사용하면 루트 안에서 정의할 수 있고 문제 없이 사용할 수 있습니다.
  4. 쉐도우 파트 사용: 새로운

선택기를 사용하면 쉐도우 트리의 일부에 접근할 수 있습니다. 이를 통해 커스텀 엘리먼트의 특정 부분을 스타일링할 수 있습니다.

  1. 문자열로 스타일 전달: 스타일을 매개변수로 전달하여 <style> 블록 내부에 적용할 수 있습니다.

폼과의 통합

쉐도우 DOM의 모든 <input>, <textarea>, <select> 요소는 자동으로 포함된 폼과 연결되지 않습니다. 초기에는 DOM에 숨겨진 필드를 추가했지만, 이는 웹 컴포넌트의 캡슐화를 깨뜨렸습니다. 현재는 새로운 ElementInternals 인터페이스를 통해 커스텀 값을 사용하여 폼과 연결하고 유효성 검사를 정의할 수 있습니다. 이는 Chrome에서 구현되었으며, 다른 브라우저를 위한 폴리필도 제공됩니다.

다음 예제에서는 이 새로운 인터페이스를 사용하는 방법을 보여줍니다. 먼저 formAssociated라는 정적 값을 클래스에 추가하여 폼이 연결되었는지 여부를 결정합니다. 또한, 폼이 연결될 때 호출되는 콜백을 추가할 수 있습니다.

class InputPwd extends HTMLElement {
  static formAssociated = true;

  formAssociatedCallback(form) {
    console.log('form is associated:', form.id);
  }
}

 

 

그런 다음 생성자에서 attachInternals() 메서드를 호출하여 컴포넌트가 폼이나 다른 요소와 통신할 수 있게 합니다. 또한 setValue 메서드를 구현하여 폼에 값을 설정합니다.

constructor() {
  super();
  this.internals = this.attachInternals();
  this.setValue('');
}

setValue(v) {
  this.value = v;
  this.internals.setFormValue(v);
}

 

 

이제 연결된 콜백 메서드를 생성하여 쉐도우 DOM을 만들고 변경 사항을 부모 폼에 전달합니다.

connectedCallback() {
  const shadow = this.attachShadow({ mode: 'closed' });

  shadow.innerHTML = `
    <style>input { width: 8em; }</style>
    <input placeholder="Password" />`;

  shadow.querySelector('input').addEventListener('input', e => {
    this.setValue(e.target.value);
  });
}

 

 

이제 웹 컴포넌트를 포함할 HTML 폼을 생성할 수 있습니다.

<form id="globalForm">
  <input type="text" name="user-email" placeholder="email" />
  <input-pwd name="user-pwd"></input-pwd>
  <button>Login</button>
</form>

 

 

의존성 주입

웹 컴포넌트를 프로그래밍할 때 컴포넌트를 재사용 가능하게 만들기 위해 의존성 주입이 필요할 수 있습니다. 이를 위해 생성자를 통해 의존성을 주입하려고 할 수 있습니다.

class MyWebComponent extends HTMLElement {
  constructor(logger: Logger, translations: TranslationService) {
    super();
    this.logger = logger;
    this.translations = translations;
  }
}

 

 

그러나 사양에 따르면 커스텀 엘리먼트가 될 때 생성자가 인수 없이 호출되므로 의존성을 전달할 수 없습니다. 이를 해결하기 위해 connectedCallback 메서드를 사용하여 의존성을 요청하고 제공할 수 있습니다.

의존성을 요청하는 웹 컴포넌트에서 connectedCallback 메서드가 실행될 때, 의존성을 제공하는 코드에서 동기 이벤트를 사용하여 이를 수행할 수 있습니다.

 

웹 컴포넌트의 수명 주기

웹 컴포넌트의 수명 주기는 정의, 생성, 기존 구조와의 연결, 연결 해제 등 다양한 단계를 거칩니다. 이러한 메서드를 수명 주기 메서드라고 합니다.

 

커스텀 엘리먼트 정의

커스텀 엘리먼트를 등록하기 위해 customElements.define() 메서드를 사용합니다. 이 메서드는 HTMLElement를 확장하는 커스텀 엘리먼트를 등록할 수 있습니다. 이를 실행하려면 몇 가지 매개변수가 필요합니다: 첫 번째는 이름, 두 번째는 요소를 정의하는 클래스, 세 번째는 옵션이 있는 객체로, 기존 커스텀 엘리먼트를 확장할 수 있게 합니다.

customElements.define(
  "custom-button",
  class CustomButton extends HTMLElement {
    // ...
  }
);

 

 

생성자

생성자는 웹 컴포넌트의 수명 주기에서 첫 번째 메서드로, 웹 컴포넌트가 초기화되었을 때 한 번 실행됩니다. super()를 호출하여 확장하는 클래스의 속성, 이벤트, 메서드를 사용할 수 있습니다.

constructor() {
  super();
  this.attachShadow({ mode: "open" });
  this.shadowRoot.appendChild(template.content.cloneNode(true));
}

 

 

super()를 호출한 후, 쉐도우 DOM에 새로운 요소를 추가해야 합니다. "open" 모드로 추가하면 JavaScript로 접근할 수 있으며, "close" 모드로 추가하면 닫힙니다. 쉐도우 루트에 추가한 후, 콘텐츠에 접근하거나 자식을 추가할 수 있습니다.

 

connectedCallback()

이 메서드는 컴포넌트가 DOM에 추가될 때마다 호출됩니다. 예를 들어, DOM에서 제거되었다가 다시 추가되면 이 메서드도 실행됩니다. 이 메서드는 특정 속성, 자식에 접근하거나 리스너를 추가하는 데 사용됩니다.

connectedCallback() {
  this.addEventListener("click", this.onclick);
}

onclick() {
  console.log("clicked handled");
}

 

 

attributeChangedCallback()

이 메서드는 특정 속성에 대한 업데이트를 수신하는 데 사용됩니다. 이를 위해, 이러한 속성을 static observedAttributes() 메서드 내에 정의해야 합니다. 한 번 정의되면, attributeChangedCallback() 메서드는 속성 변경 후 실행됩니다. 이 메서드에는 세 가지 매개변수가 있습니다: 첫 번째는 수정된 속성의 이름, 두 번째는 이전 값, 세 번째는 새 값입니다. 이 메서드는 setAttribute() 메서드가 실행되었을 때만 변경된 것으로 간주됩니다.

static get observedAttributes() {
  return ["disabled"];
}

attributeChangedCallback(attrName, oldVal, newVal) {
  if (attrName === "disabled") {
    this.shadowRoot.getElementById("button").disabled = newVal === "true";
  }
}

set disabled(bool) {
  this.setAttribute("disabled", bool.toString());
}

get disabled() {
  return this.getAttribute("disabled") === "true";
}

 

 

adoptedCallback()

이 메서드는 웹 컴포넌트가 한 문서에서 다른 문서로 이동되었음을 알리는 데 사용됩니다. document.adoptNode() 메서드가 호출되었을 때만 실행됩니다.

adoptedCallback() {
  console.log("moved to a new document");
}

 

 

disconnectedCallback()

이 메서드는 웹 컴포넌트가 DOM에서 제거되었을 때만 호출되어 더 이상 표시되지 않음을 알립니다. 일반적으로 리스너를 제거하고 구독을 해제하는 데 사용됩니다.

disconnectedCallback() {
  this.removeEventListener("click", this.onclick);
}

 

 

Angular와의 통합

웹 컴포넌트의 강점 중 하나는 다양한 프레임워크 및 라이브러리와의 통합입니다. 다음은 Angular와 웹 컴포넌트를 통합하는 간단한 예시입니다.

우선, Angular 프로젝트를 생성하고 할 일 목록 컴포넌트를 만듭니다. 이 컴포넌트는 특별한 것이 없으며, 일반적인 Angular 컴포넌트입니다. 또한, 할 일 목록의 이름을 입력으로 받습니다.

컴포넌트를 생성한 후, app.module 파일을 수정하여 컴포넌트를 웹 컴포넌트로 내보낼 수 있게 합니다. 이를 위해 Angular Elements 라이브러리를 사용합니다. 필요한 모든 작업은 다음과 같습니다:

  1. 부트스트랩에서 AppComponent를 제거합니다.
  2. 생성한 할 일 목록 컴포넌트를 entryComponent로 추가합니다.
  3. @angular/elements 패키지를 설치합니다.
  4. ngDoBootstrap 훅 안에서 createCustomElement 메서드를 사용하여 컴포넌트를 표준 웹 컴포넌트로 컴파일합니다.

이제 프로젝트를 컴파일하면 dist 디렉토리에 runtime, main, scripts, polyfills라는 파일들이 생성됩니다. 생성된 웹 컴포넌트는 다른 프로젝트에서 사용할 수 있습니다.

 

도구

웹 컴포넌트 개발을 쉽게 하고 통합 및 유지 관리를 원활하게 하기 위해 여러 라이브러리가 등장했습니다. 이러한 도구는 주로 개발 경험을 향상시키고 개발을 빠르게 할 수 있도록 도와줍니다. 주요 브랜드인 Apple, Porsche, Amazon 등에서도 사용하고 있습니다.

 

Stencil

Stencil.js Ionic 팀이 다른 프레임워크와의 호환성을 열기 위해 만든 도구입니다. Ionic은 원래 Angular와만 작동했으나, Stencil 덕분에 현재 React, Vue, 다른 프레임워크와 원활하게 작동할 수 있습니다. Stencil Vanilla JavaScript로 작성된 웹 컴포넌트 컴파일러입니다. React의 가상 DOM, 서버 사이드 렌더링, 반응형 데이터 바인딩, React Fiber에서 영감을 받은 비동기 렌더링 등 다양한 프레임워크의 장점을 가지고 있습니다. 또한 TypeScript JSX를 템플릿 엔진으로 지원하고, Webpack 없이도 지연 로딩을 사용할 수 있습니다.

 

Polymer

Polymer Google이 내부 프로젝트를 위해 개발한 라이브러리로, 나중에 공개되었습니다. 이 라이브러리는 웹 컴포넌트가 대부분의 브라우저에서 네이티브로 호환될 수 있게 하는 여러 폴리필을 제공합니다. 이 라이브러리를 사용하면 웹 컴포넌트를 더 쉽고 빠르게 만들 수 있습니다.

 

결론

웹 컴포넌트는 다양한 프레임워크 및 라이브러리와 호환되며, 재사용 가능한 컴포넌트를 만들고 유지 보수를 간편하게 할 수 있는 강력한 도구입니다. 웹 컴포넌트의 주요 사양과 호환성, 도전 과제 등을 이해하고 적절히 활용하면, 효율적인 웹 개발이 가능합니다. Stencil Polymer와 같은 도구를 활용하면 웹 컴포넌트를 더 쉽게 개발하고 통합할 수 있습니다. 웹 컴포넌트를 통해 통일된 브랜드 이미지와 유지 보수의 편리함을 동시에 누릴 수 있습니다.

반응형