{"id":26117,"date":"2024-01-02T05:00:00","date_gmt":"2024-01-02T04:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=26117"},"modified":"2024-07-22T14:21:03","modified_gmt":"2024-07-22T12:21:03","slug":"web-components-tworzenie-od-zera-niestandardowych-elementow-html","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/web-components-tworzenie-od-zera-niestandardowych-elementow-html\/","title":{"rendered":"Web Components \u2013 tworzenie od zera niestandardowych element\u00f3w HTML"},"content":{"rendered":"\n<p>Mimo \u017ce historia komponent\u00f3w w architekturze frontendowej si\u0119ga lat 90-tych, dopiero po roku 2010, wraz z rozwojem JavaScriptowych bibliotek i framework\u00f3w, sta\u0142y si\u0119 one standardem. Skoro jednak Angular, React, czy Vue.js dostarczaj\u0105 nam kompleksowe rozwi\u0105zania oparte na komponentach, to czy jest pow\u00f3d, by wspiera\u0107 si\u0119 alternatywnym podej\u015bciem, jakim s\u0105 komponenty webowe?<\/p>\n\n\n\n<p>Zdecydowanie tak \u2013 przede wszystkim dlatego, \u017ce korzystaj\u0105c z frameworka, jeste\u015bmy zwi\u0105zani jego rozwi\u0105zaniami. <strong>Web Components s\u0105 natomiast elementami natywnymi, co zapewnia bezcenn\u0105 elastyczno\u015b\u0107<\/strong>. Argument\u00f3w jest jednak wi\u0119cej, a przybli\u017c\u0119 je w artykule.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Czym s\u0105 komponenty webowe?<\/strong><\/h2>\n\n\n\n<p>Najpro\u015bciej m\u00f3wi\u0105c, komponenty webowe to zestaw standard\u00f3w i technologii umo\u017cliwiaj\u0105cych tworzenie element\u00f3w interfejsu u\u017cytkownika, kt\u00f3re s\u0105 autonomiczne, odizolowane, gotowe do komponowania i wielokrotnego u\u017cywania. Sk\u0142adaj\u0105 si\u0119 przede wszystkim z:<\/p>\n\n\n\n<ol class=\"wp-block-list\" type=\"1\">\n<li>Custom Elements \u2013 technologii, dzi\u0119ki kt\u00f3rej mo\u017cemy tworzy\u0107 elementy HTML dzia\u0142aj\u0105ce tak samo, jak te znane nam ze standardu HTML (&lt;p&gt;, &lt;div&gt;, etc.).<\/li>\n\n\n\n<li>HTML Templates \u2013 pozwalaj\u0105cych na tworzenie szablon\u00f3w HTML gotowych do u\u017cytku w wielu miejscach.<\/li>\n\n\n\n<li>Shadow DOM \u2013 dzi\u0119ki kt\u00f3remu stworzymy alternatywne, odizolowane drzewo DOM dla r\u00f3\u017cnych element\u00f3w, a jego skrypty i style b\u0119d\u0105 niezale\u017cne od tych u\u017cytych na zewn\u0105trz.<\/li>\n\n\n\n<li>HTML Imports \u2013 przestarza\u0142e, ale skutecznie zast\u0105pione, m.in.: przez ES Modules, rozwi\u0105zanie umo\u017cliwiaj\u0105ce wpinanie element\u00f3w do innych plik\u00f3w HTML.<\/li>\n<\/ol>\n\n\n\n<p>Technologie te razem pozwalaj\u0105 osi\u0105gn\u0105\u0107 podobne zyski, jak znane nam frameworki i biblioteki JS, z t\u0105 r\u00f3\u017cnic\u0105, \u017ce <strong>stawiaj\u0105c na komponenty webowe, jeste\u015bmy bardziej niezale\u017cni<\/strong>. Mi\u0119dzy innymi dlatego, mimo popularno\u015bci Angulara czy Reacta, nie odesz\u0142y do lamusa, a przeciwnie \u2013 po tym jak zosta\u0142y formalnie uznane przez W3C, <strong>nieustannie zyskuj\u0105 na popularno\u015bci<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Pocz\u0105tki<\/strong><\/h2>\n\n\n\n<p>Mniej wi\u0119cej we wspomnianym 2010 roku zacz\u0119to podnosi\u0107 problemy, jakie wynikaj\u0105 z dotychczas stosowanych standard\u00f3w tworzenia interfejsu u\u017cytkownika. Komponenty webowe jako jeszcze niesformalizowana technologia polegaj\u0105ca na stosowaniu samowystarczalnych, reu\u017cywalnych element\u00f3w, zacz\u0119\u0142y by\u0107 stosowane ju\u017c w roku 2011.<\/p>\n\n\n\n<p>W rozwijanie tej koncepcji od pocz\u0105tku zaanga\u017cowana by\u0142a nie tylko spo\u0142eczno\u015b\u0107 developer\u00f3w i rozmaite organizacje, ale i du\u017ce firmy jak Google, Apple czy Microsoft. W 2014 roku W3C zacz\u0119\u0142o wieloletni\u0105 prac\u0119 nad ustandaryzowaniem Web Components, a rozwi\u0105zania, kt\u00f3re obejmuje, zacz\u0119\u0142y by\u0107 stopniowo obs\u0142ugiwane przez przegl\u0105darki. W3C publikowa\u0142o r\u00f3\u017cne materia\u0142y na ten temat w roku 2018 i 2019, ale ostateczny standard pojawi\u0142 si\u0119 w styczniu roku 2021.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Dlaczego warto?<\/strong><\/h2>\n\n\n\n<p>Powod\u00f3w, dla kt\u00f3rych coraz wi\u0119cej aplikacji korzysta z rozwi\u0105za\u0144 dostarczanych przez Web Components, jest sporo, cho\u0107 jak pisa\u0142em \u2013 wi\u0119kszo\u015b\u0107 tych zalet znamy z innych JS-owych bibliotek i framework\u00f3w:<\/p>\n\n\n\n<ol class=\"wp-block-list\" type=\"1\">\n<li>Mo\u017cliwo\u015b\u0107 wielokrotnego zastosowania \u2013 komponenty s\u0105 wyizolowane, samowystarczalne (o ile nie potrzebuj\u0105 danych do zaprezentowania) i \u0142atwe w implementacji. Znacz\u0105co ogranicza to potrzeb\u0119 duplikowania kodu,.<\/li>\n\n\n\n<li>\u0141atwo\u015b\u0107 utrzymania \u2013 tak skonstruowane komponenty maj\u0105 niedu\u017cy wp\u0142yw na ca\u0142o\u015b\u0107 aplikacji, co u\u0142atwia aktualizowanie i utrzymywanie.<\/li>\n\n\n\n<li>Niezale\u017cne style i funkcjonalno\u015bci \u2013 dzi\u0119ki Shadow DOM minimalizujemy ryzyko konflikt\u00f3w.<\/li>\n\n\n\n<li>\u0141atwo\u015b\u0107 testowania \u2013 podzia\u0142 na takie komponenty umo\u017cliwia oddzielne testowanie.<\/li>\n\n\n\n<li>Przejrzysto\u015b\u0107 kodu \u2013 aplikacja oparta na tych rozwi\u0105zaniach jest bardziej czytelna i \u0142atwiejsza w zrozumieniu dla developera.<\/li>\n\n\n\n<li>Bardziej efektywna praca w zespo\u0142ach \u2013 wielokrotne u\u017cywanie tych samych komponent\u00f3w u\u0142atwia wsp\u00f3\u0142prac\u0119 pomi\u0119dzy korzystaj\u0105cymi z nich zespo\u0142ami.<\/li>\n\n\n\n<li>Standaryzacja \u2013 osi\u0105gni\u0119ta standaryzacja sprawia, \u017ce koncepcja jest sp\u00f3jna i przewidywalna,<\/li>\n\n\n\n<li>\u0141atwa integracja \u2013 zdecydowanie najwa\u017cniejsza zaleta w kontek\u015bcie popularno\u015bci framework\u00f3w to mo\u017cliwo\u015b\u0107 wykorzystywania komponent\u00f3w webowych niezale\u017cnie od innych u\u017cywanych w aplikacji rozwi\u0105za\u0144.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Technologie<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Custom Elements<\/strong><\/h3>\n\n\n\n<p>W roku 2011 spod r\u0105k Alexa Russella (Google) i Eduardo Lundgrena (Liferay) wysz\u0142a koncepcja \u201ewebkitCustomElement\u201d zastosowana w projekcie WebKi, czyli silniku u\u017cywanym m.in.: przez Safari. Ten prototyp sta\u0142 si\u0119 zal\u0105\u017ckiem Custom Elements v0, kt\u00f3re w 2013 roku zosta\u0142y cz\u0119\u015bci\u0105 specyfikacji \u201eHTML Living Standard\u201d, by ostatecznie ewoluowa\u0107 w roku 2016 w Custom Elements v1, ustandaryzowane w W3C. Od tamtej pory kolejne przegl\u0105darki implementowa\u0142y to rozwi\u0105zanie, a same Custom Elements sta\u0142y si\u0119 podstaw\u0105 i najwa\u017cniejszym elementem komponent\u00f3w webowych.<\/p>\n\n\n\n<p>Pozwalaj\u0105 one kreowa\u0107 niemal dowolne elementy HTML, kt\u00f3re nie s\u0105 cz\u0119\u015bci\u0105 tego standardu. Ich tworzenie odbywa si\u0119 w trzech prostych krokach.<\/p>\n\n\n\n<p>Na pocz\u0105tku definiujemy komponent przy u\u017cyciu metody:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz1.png\"><img decoding=\"async\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz1.png\" alt=\"kod\" class=\"wp-image-26118\" width=\"220\" height=\"23\"\/><\/a><\/figure>\n\n\n\n<p>Podajemy te\u017c nazw\u0119 elementu oraz klas\u0119. Nast\u0119pnie dodajemy funkcjonalno\u015bci, definiuj\u0105c metody w klasie. Na koniec przy u\u017cyciu konstruktora tworzymy instancj\u0119 komponentu.<\/p>\n\n\n\n<p>To, co wymaga kr\u00f3tkiego om\u00f3wienia, to znany nam z framework\u00f3w JS cykl \u017cycia nowo utworzonego elementu. Wykonywanie akcji na r\u00f3\u017cnych etapach u\u0142atwia kontrol\u0119 nad komponentami. Mamy do dyspozycji m.in.:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>connectedCallback, gdy nasz element trafia do drzewa DOM,<\/li>\n\n\n\n<li>disconnectedCallback, gdy zostaje z niego usuni\u0119ty,<\/li>\n\n\n\n<li>attributeChangedCallback, gdy jego atrybut zostanie zmieniony,<\/li>\n\n\n\n<li>adoptedCallback, gdy element zostanie przeniesiony.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz2.jpg\"><img decoding=\"async\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz2.jpg\" alt=\"Custom Element \u2013 schemat lifecycle \" class=\"wp-image-26120\" width=\"564\" height=\"474\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz2.jpg 788w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz2-300x252.jpg 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz2-768x645.jpg 768w\" sizes=\"(max-width: 564px) 100vw, 564px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 1 <a href=\"https:\/\/javascript.works-hub.com\/learn\/web-components-api-lifecycle-events-and-custom-events-66668\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Custom Element \u2013 schemat lifecycle<\/a><\/figcaption><\/figure>\n\n\n\n<p>Przyk\u0142adowe u\u017cycie Custom Element:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz3.png\"><img decoding=\"async\" width=\"427\" height=\"271\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz3.png\" alt=\"kod\" class=\"wp-image-26122\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz3.png 427w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz3-300x190.png 300w\" sizes=\"(max-width: 427px) 100vw, 427px\" \/><\/a><\/figure>\n\n\n\n<p>HTML:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz4.png\"><img decoding=\"async\" width=\"355\" height=\"123\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz4.png\" alt=\"kod\" class=\"wp-image-26124\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz4.png 355w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz4-300x104.png 300w\" sizes=\"(max-width: 355px) 100vw, 355px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Shadow DOM<\/strong><\/h3>\n\n\n\n<p>Technologia Shadow DOM, kt\u00f3ra tak\u017ce w 2011 roku zosta\u0142a przedstawiona przez Google, umo\u017cliwia tworzenie izolowanych drzew DOM dla r\u00f3\u017cnych element\u00f3w \u2013 takie drzewa nie s\u0105 dost\u0119pne poza komponentem. Dzi\u0119ki temu unikamy konflikt\u00f3w skrypt\u00f3w oraz styl\u00f3w i uzyskujemy czystszy kod. Izolacja komponent\u00f3w mo\u017ce by\u0107 zrealizowana na jednym z trzech poziom\u00f3w:<\/p>\n\n\n\n<ol class=\"wp-block-list\" type=\"1\">\n<li>Open Shadow DOM \u2013 mamy tu ograniczony poziom hermetyzacji, wybieraj\u0105c go, mo\u017cemy sprawi\u0107, \u017ce cz\u0119\u015b\u0107 element\u00f3w b\u0119dzie dost\u0119pna na zewn\u0105trz. By tak si\u0119 sta\u0142o, atrybut `mode` musi by\u0107 ustawiony na `open` w metodzie `attachShadow()`, gdy Shadow DOM jest tworzony. Wi\u0119kszo\u015b\u0107 styl\u00f3w i skrypt\u00f3w pozostaje jednak w dalszym ci\u0105gu izolowana.<\/li>\n\n\n\n<li>Closed Shadow DOM \u2013 na tym poziomie dost\u0119p mo\u017cliwy jest tylko przez API Shadow DOM.<\/li>\n\n\n\n<li>Scoped Shadow DOM \u2013 elementy s\u0105 ca\u0142kowicie niedost\u0119pne na zewn\u0105trz. Ten poziom osi\u0105gamy, stosuj\u0105c odpowiednie selektory CSS, jak :host i ::slotted, by zdefiniowa\u0107, jakie style b\u0119d\u0105 stosowane w ramach Shadow DOM i co ma zosta\u0107 przeniesione na zewn\u0105trz komponentu.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5.jpg\"><img decoding=\"async\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5-1024x530.jpg\" alt=\"Schemat Shadow DOM \" class=\"wp-image-26126\" width=\"840\" height=\"434\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5-1024x530.jpg 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5-300x155.jpg 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5-768x398.jpg 768w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5.jpg 1201w\" sizes=\"(max-width: 840px) 100vw, 840px\" \/><\/a><figcaption class=\"wp-element-caption\">Ryc. 2. <a href=\"https:\/\/www.ionos.com\/digitalguide\/websites\/web-development\/shadow-dom\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Schemat Shadow DOM<\/a><\/figcaption><\/figure>\n\n\n\n<p>A jak wygl\u0105da implementacja Shadow DOM? Poni\u017cej prosty przyk\u0142ad, w kt\u00f3rym elementy `h1` oraz `p` nie s\u0105 widoczne na stronie, za to pozostaj\u0105 dost\u0119pne przez JS:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5.png\"><img decoding=\"async\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5.png\" alt=\"kod\" class=\"wp-image-26129\" width=\"535\" height=\"388\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5.png 535w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz5-300x218.png 300w\" sizes=\"(max-width: 535px) 100vw, 535px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>HTML Templates<\/strong><\/h3>\n\n\n\n<p>Technologi\u0119 HTML Templates zapocz\u0105tkowa\u0142 element `&lt;template&gt;`, kt\u00f3ry w 2009 roku pojawi\u0142 si\u0119 w specyfikacji HTML5. W kolejnych latach rozwa\u017cano jego u\u017cycie przy tworzeniu komponent\u00f3w interfejsu u\u017cytkownika, by w 2013 roku sta\u0142 si\u0119 oficjalnie cz\u0119\u015bci\u0105 ekosystemu komponent\u00f3w webowych.<\/p>\n\n\n\n<p>M\u00f3wi\u0105c najpro\u015bciej, jest to mechanizm pozwalaj\u0105cy zdefiniowa\u0107 cz\u0119\u015bci kodu HTML, kt\u00f3re nie b\u0119d\u0105 renderowane podczas \u0142adowania, mog\u0105 by\u0107 jednak przechowywane jako szablony i co najwa\u017cniejsze \u2013 u\u017cywane do dynamicznego generowania tre\u015bci w czasie wykonania.<\/p>\n\n\n\n<p>HTML Templates maj\u0105 kilka zalet, a najwa\u017cniejsze z nich to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>oddzielenie logiki od prezentacji, co wp\u0142ywa na organizacj\u0119 kodu,<\/li>\n\n\n\n<li>mo\u017cliwo\u015b\u0107 wielokrotnego u\u017cycia,<\/li>\n\n\n\n<li>wsparcie bezpiecze\u0144stwa \u2013 pomagaj\u0105 unikn\u0105\u0107 atak\u00f3w typu XSS (Cross-Site Scripting), zapobiegaj\u0105c wstrzykiwaniu niebezpiecznego kodu do danych.<\/li>\n<\/ul>\n\n\n\n<p>HTML Templates s\u0105 r\u00f3wnie proste w implementacji, co inne rozwi\u0105zania z zakresu Web Components:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz6.png\"><img decoding=\"async\" width=\"231\" height=\"122\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz6.png\" alt=\"kod\" class=\"wp-image-26131\"\/><\/a><\/figure>\n\n\n\n<p>JS:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz7.png\"><img decoding=\"async\" width=\"537\" height=\"142\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz7.png\" alt=\"kod\" class=\"wp-image-26133\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz7.png 537w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz7-300x79.png 300w\" sizes=\"(max-width: 537px) 100vw, 537px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>HTML Imports oraz ES Modules<\/strong><\/h3>\n\n\n\n<p>Pomys\u0142 wykorzystania elementu `&lt;link&gt;`, by importowa\u0107 dokumenty HTML zawieraj\u0105ce m.in.: kod komponent\u00f3w, pojawi\u0142 si\u0119 w 2011 roku. Rok p\u00f3\u017aniej powsta\u0142a specyfikacja dla HTML Imports, zak\u0142adaj\u0105ca wykorzystanie atrybutu `rel` elementu `&lt;link&gt;`. Korzystanie w przegl\u0105darkach z elementu `&lt;link rel=&#8221;import&#8221;&gt;` zacz\u0119\u0142o by\u0107 mo\u017cliwe w roku 2014, jednak ju\u017c dwa lata p\u00f3\u017aniej rozwi\u0105zanie to zacz\u0119\u0142o by\u0107 wypierane przez ES Modules, oferuj\u0105ce metod\u0119 bardziej elastyczn\u0105 i zgodn\u0105 z ECMAScript 6.<\/p>\n\n\n\n<p>Nie mniej, zar\u00f3wno HTML Imports jak i ES Modules to mechanizmy umo\u017cliwiaj\u0105ce importowanie oraz organizowanie zewn\u0119trznych skrypt\u00f3w i modu\u0142\u00f3w w aplikacji. R\u00f3\u017cni\u0105 si\u0119 g\u0142\u00f3wnie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Sk\u0142adnia \u2013 odpowiednio `&lt;link rel=&#8221;import&#8221; href=&#8221;\u015bcie\u017cka.html&#8221;&gt;` dla HTML Imports i `import, np.: import { funkcja } from '\u015bcie\u017cka&#8217;;` dla ES Modules. Warto tu wspomnie\u0107, \u017ce pierwsze z tych rozwi\u0105za\u0144 skutkuje importem wszystkich zale\u017cno\u015bci, podczas gdy modu\u0142y ES Modules zawieraj\u0105 tylko to, co zosta\u0142o zaimportowane bezpo\u015brednio.<\/li>\n\n\n\n<li>Zakres \u2013 HTML Imports umo\u017cliwia jedynie import globalny, nara\u017camy si\u0119 wi\u0119c na wyst\u0105pienie konflikt\u00f3w nazw. ES Modules maj\u0105 w\u0142asne zakresy.<\/li>\n\n\n\n<li>Wsparcie \u2013 HTML Imports nie s\u0105 wspierane przez nowsze przegl\u0105darki, analogicznie ES Modules maj\u0105 problem ze wsparciem tych starszych. Rozwi\u0105zaniem w obu przypadkach mog\u0105 by\u0107 polyfille (np. Babel).<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Przechwytywanie.jpg\" alt=\"\" class=\"wp-image-26136\" width=\"617\" height=\"416\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Przechwytywanie.jpg 958w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Przechwytywanie-300x202.jpg 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Przechwytywanie-768x518.jpg 768w\" sizes=\"(max-width: 617px) 100vw, 617px\" \/><figcaption class=\"wp-element-caption\">Ryc. 3 <a href=\"https:\/\/hacks.mozilla.org\/2018\/03\/es-modules-a-cartoon-deep-dive\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >HTML Imports i ES Modules<\/a><\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Kt\u00f3re wybra\u0107?<\/strong><\/h3>\n\n\n\n<p>Kiedy si\u0119gn\u0105\u0107 po HTML Imports, a kiedy po ES Modules?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>HTML Imports \u2013 b\u0119d\u0105 pomocne przy pracy ze starszymi przegl\u0105darkami lub wtedy, gdy chcemy \u015bwiadomie zaimportowa\u0107 pe\u0142ny pakiet zale\u017cno\u015bci.<\/li>\n\n\n\n<li>ES Modules \u2013 gdy pracujemy w nowszym projekcie i korzystamy z ES co najmniej w wersji 6 oraz potrzebujemy wi\u0119kszej izolacji. Na ES Modules warto postawi\u0107 r\u00f3wnie\u017c wtedy, gdy przydadz\u0105 nam si\u0119 dostarczane przez nie rozwi\u0105zania jak eksport domy\u015blny, kt\u00f3ry pozwala na eksportowanie jednej warto\u015bci lub obiektu jako domy\u015blnego eksportu z modu\u0142u (to oznacza, \u017ce mo\u017cna zdefiniowa\u0107 jedno g\u0142\u00f3wne wyj\u015bcie modu\u0142u, kt\u00f3re jest u\u017cywane jako warto\u015b\u0107 domy\u015blna, gdy inny modu\u0142 importuje ten modu\u0142 bez podawania konkretnej nazwy eksportowanej warto\u015bci).<\/li>\n<\/ul>\n\n\n\n<p>Standardem jest ju\u017c jednak korzystanie z ES Modules i ewentualne wykorzystanie narz\u0119dzi umo\u017cliwiaj\u0105cych wsparcie starszych przegl\u0105darek.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wbudowane i zewn\u0119trzne komponenty webowe<\/strong><\/h2>\n\n\n\n<p>W standardzie HTML mamy ju\u017c sporo przydatnych wbudowanych Web Components. S\u0105 to m.in.: `&lt;select&gt;` czy `&lt;input&gt;` umo\u017cliwiaj\u0105ce u\u017cytkownikowi wprowadzenie warto\u015bci, `&lt;video&gt;` i `&lt;audio&gt;`, dzi\u0119ki kt\u00f3rym mo\u017cemy osadzi\u0107 pliki d\u017awi\u0119kowe oraz wideo, czy wreszcie `&lt;canvas&gt;`, kt\u00f3ry pozwala tworzy\u0107 grafiki lub animacje.<\/p>\n\n\n\n<p>Nieco ciekawsze s\u0105 komponenty, kt\u00f3re znajdziemy w zewn\u0119trznych bibliotekach. Warto tu si\u0119gn\u0105\u0107 po takie zbiory jak Google\u2019owskie LitElement oraz Polymer lub Stencil czy Ionic. Wi\u0119kszo\u015b\u0107 z nich \u0142atwo zaimplementowa\u0107 przy pomocy NPM lub link\u00f3w CDN.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Komunikacja<\/strong><\/h2>\n\n\n\n<p>Komunikacja mi\u0119dzy komponentami webowymi mo\u017ce si\u0119 odbywa\u0107 na kilka sposob\u00f3w. Najwa\u017cniejsze z nich om\u00f3wi\u0142em poni\u017cej.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Eventy<\/strong><\/h3>\n\n\n\n<p>To kluczowy mechanizm s\u0142u\u017c\u0105cy do komunikacji mi\u0119dzy komponentami. Dzi\u0119ki niemu mo\u017cemy przekaza\u0107 informacje o zdarzeniach i zmianach, co stanowi podstaw\u0119 interakcji wewn\u0105trz aplikacji.<\/p>\n\n\n\n<p>Komponent, chc\u0105c wys\u0142a\u0107 event, powinien stworzy\u0107 instancj\u0119 obiektu Event albo potomka klasy CustomEvent. Nast\u0119pnie nale\u017cy u\u017cy\u0107 metody dispatchEvent() na danym elemencie HTML \u2013 b\u0119dzie on emitentem eventu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz8.png\"><img decoding=\"async\" width=\"463\" height=\"42\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz8.png\" alt=\"kod\" class=\"wp-image-26138\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz8.png 463w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz8-300x27.png 300w\" sizes=\"(max-width: 463px) 100vw, 463px\" \/><\/a><\/figure>\n\n\n\n<p>Do nas\u0142uchiwania s\u0142u\u017cy z kolei metoda `addEventListener()`. Po emisji nas\u0142uchuj\u0105cy komponent przechwytuje event i wykonuje akcj\u0119:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz9.png\"><img decoding=\"async\" width=\"486\" height=\"54\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz9.png\" alt=\"kod\" class=\"wp-image-26141\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz9.png 486w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz9-300x33.png 300w\" sizes=\"(max-width: 486px) 100vw, 486px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Propagowanie event\u00f3w<\/strong><\/h3>\n\n\n\n<p>W zwi\u0105zku z tym, \u017ce eventy nie s\u0105 w stanie wyj\u015b\u0107 poza Shadow DOM, korzystaj\u0105c z niego, musimy u\u017cy\u0107 jego w\u0142asnego mechanizmu propagacji. W tym celu wykorzystamy opcj\u0119 `composed` ustawion\u0105 na `true`:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz10.png\"><img decoding=\"async\" width=\"605\" height=\"50\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz10.png\" alt=\"kod\" class=\"wp-image-26143\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz10.png 605w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz10-300x25.png 300w\" sizes=\"(max-width: 605px) 100vw, 605px\" \/><\/a><\/figure>\n\n\n\n<p>Z kolei nas\u0142uchiwanie skonstruujemy tak:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz11.png\"><img decoding=\"async\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz11.png\" alt=\"kod\" class=\"wp-image-26145\" width=\"419\" height=\"55\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz11.png 419w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Obraz11-300x39.png 300w\" sizes=\"(max-width: 419px) 100vw, 419px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Przekazywanie danych pomi\u0119dzy komponentami<\/strong><\/h3>\n\n\n\n<p>Samo przekazywanie danych mo\u017cemy zrealizowa\u0107 przez:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Wykorzystanie atrybut\u00f3w \u2013 emiter przekazuje dane w atrybucie elementu HTML, z kolei element nas\u0142uchuj\u0105cy wykorzystuje metod\u0119 `getAttribute()` lub kt\u00f3re\u015b z rozwi\u0105za\u0144 dost\u0119pnych w zewn\u0119trznych bibliotekach.<\/li>\n\n\n\n<li>CustomEvent \u2013 taki obiekt w atrybucie `detail` mo\u017ce zawiera\u0107 z\u0142o\u017cone dane dost\u0119pne dla komponentu nas\u0142uchuj\u0105cego.<\/li>\n\n\n\n<li>Wsp\u00f3lne zmienne \u2013 wystarczy, by zmienna przechowuj\u0105ca dane mia\u0142a zakres, kt\u00f3ry b\u0119dzie dost\u0119pny dla ca\u0142ego DOM lub zakres globalny.<\/li>\n\n\n\n<li>Biblioteki do zarz\u0105dzania stanem \u2013 je\u015bli nasza aplikacja jest bardziej z\u0142o\u017cona, warto si\u0119gn\u0105\u0107 po rozwi\u0105zania dostarczane przez Redux, Mobx lub Vuex.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Bezpiecze\u0144stwo<\/strong><\/h2>\n\n\n\n<p>Decyduj\u0105c si\u0119 na korzystanie z komponent\u00f3w webowych, musimy by\u0107 \u015bwiadomi r\u00f3\u017cnych zagro\u017ce\u0144, m.in.: atak\u00f3w typu Cross-Site Request Forgery, Cross-Site Scripting czy te\u017c zwi\u0105zanych z zarz\u0105dzaniem danymi, bibliotekami lub aktualizacjami.<\/p>\n\n\n\n<p>Przed du\u017c\u0105 cz\u0119\u015bci\u0105 z nich zabezpieczymy si\u0119, pilnuj\u0105c przestrzegania kilku zasad:<\/p>\n\n\n\n<ol class=\"wp-block-list\" type=\"1\">\n<li>Pilnowanie uprawnie\u0144 \u2013 komponent powinien wp\u0142ywa\u0107 wy\u0142\u0105cznie na przypisany do niego element DOM, nie ingeruj\u0105c w inne elementy oraz w ich zawarto\u015b\u0107.<\/li>\n\n\n\n<li>Ostro\u017cna wymiana danych \u2013 korzystanie z atrybut\u00f3w czy Custom Events to bezpieczne formy wymiany danych i tylko tego typu form powinni\u015bmy si\u0119 trzyma\u0107.<\/li>\n\n\n\n<li>Aktualizacje i testy bezpiecze\u0144stwa \u2013 jedno i drugie powinno by\u0107 przeprowadzane regularnie.<\/li>\n\n\n\n<li>Walidacja \u2013 atakom typu XSS oraz wyciekom zapobiegniemy, filtruj\u0105c i waliduj\u0105c dane wykorzystywane do generowania tre\u015bci.<\/li>\n\n\n\n<li>Unikanie niebezpiecznych mechanizm\u00f3w \u2013 np. funkcja `eval()` pozwala wykona\u0107 kod jako string; takie rozwi\u0105zania mog\u0105 zosta\u0107 u\u017cyte przeciwko nam.<\/li>\n\n\n\n<li>Shadow DOM \u2013 do jego licznych zalet nale\u017cy m.in.: izolacja styl\u00f3w i logiki, co zapobiega nie tylko konfliktom, ale i manipulacjom.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Integracja z frameworkami, bibliotekami i narz\u0119dziami developerskimi, post\u0119puj\u0105ca standaryzacja oraz nowe specyfikacje dowodz\u0105, \u017ce popularno\u015b\u0107 Web Components stale ro\u015bnie. Trudno si\u0119 dziwi\u0107 \u2013 dzi\u0119ki nim zyskujemy mo\u017cliwo\u015b\u0107 wielokrotnego u\u017cywania tych samych element\u00f3w, izolacj\u0119, popraw\u0119 bezpiecze\u0144stwa, czy niezale\u017cno\u015b\u0107 od framework\u00f3w.<\/p>\n\n\n\n<p>Nie jest ju\u017c praktycznie mo\u017cliwe tworzenie warstwy frontendowej aplikacji z pomini\u0119ciem standard\u00f3w tej technologii, dlatego nawet je\u015bli nie u\u017cywamy jej w projekcie bezpo\u015brednio, warto by\u0107 na bie\u017c\u0105co z tym, co s\u0142ycha\u0107 w \u015bwiecie komponent\u00f3w webowych.<\/p>\n\n\n\n<p>***<\/p>\n\n\n\n<p>Je\u015bli interesuje Ci\u0119 tematyka &#8222;<a aria-label=\"Komponenty niestandardowe w Power Apps (opens in a new tab)\" href=\"https:\/\/sii.pl\/blog\/komponenty-niestandardowe-w-power-apps\/\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"ek-link\">Komponenty niestandardowe w Power Apps<\/a>&#8221; oraz &#8222;<a href=\"https:\/\/sii.pl\/blog\/react-stylowanie-komponentow-za-pomoca-styled-components\/\" target=\"_blank\" aria-label=\"React. Stylowanie komponent\u00f3w za pomoc\u0105 styled-components (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">React. Stylowanie komponent\u00f3w za pomoc\u0105 styled-components<\/a>&#8222;, zajrzyj koniecznie do artyku\u0142\u00f3w naszych ekspert\u00f3w. <\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;26117&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;9&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 9)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Web Components \u2013 tworzenie od zera niestandardowych element\u00f3w HTML&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 9)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Mimo \u017ce historia komponent\u00f3w w architekturze frontendowej si\u0119ga lat 90-tych, dopiero po roku 2010, wraz z rozwojem JavaScriptowych bibliotek i &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/web-components-tworzenie-od-zera-niestandardowych-elementow-html\/\">Continued<\/a><\/p>\n","protected":false},"author":572,"featured_media":26169,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[2427,1848,1675,1512,113,188],"class_list":["post-26117","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-digital","tag-komponenty-webowe","tag-moim-zdaniem","tag-poradnik","tag-frontend","tag-html"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/12\/Web-Components-tworzenie-od-zera-niestandardowych-elementow-HTML.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/26117"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/572"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=26117"}],"version-history":[{"count":3,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/26117\/revisions"}],"predecessor-version":[{"id":26148,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/26117\/revisions\/26148"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/26169"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=26117"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=26117"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=26117"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}