Yeniden Kullanılabilir Bileşenlerin Kutsal Kasesi: Özel Öğeler, Gölge DOM ve NPM

Yayınlanan: 2022-03-10
Hızlı özet ↬ Bu makale, HTML'yi yerleşik işlevsellik ve stiller içeren bileşenlerle güçlendirmeye bakar. Ayrıca, NPM kullanarak bu özel öğelerin projeler arasında nasıl yeniden kullanılabilir hale getirileceğini öğreneceğiz.

En basit bileşenler için bile insan emeğinin maliyeti önemli olabilir. UX ekipleri kullanılabilirlik testi yapar. Bir dizi paydaş tasarıma imza atmalıdır.

Geliştiriciler AB testleri, erişilebilirlik denetimleri, birim testleri ve tarayıcılar arası kontroller gerçekleştirir. Bir sorunu çözdükten sonra, bu çabayı tekrarlamak istemezsiniz . Yeniden kullanılabilir bir bileşen kitaplığı oluşturarak (her şeyi sıfırdan oluşturmak yerine), geçmişteki çabalardan sürekli olarak yararlanabilir ve halihazırda çözülmüş tasarım ve geliştirme zorluklarını yeniden gözden geçirmekten kaçınabiliriz.

Google'ın malzeme bileşenleri web sitesinin çeşitli bileşenleri gösteren ekran görüntüsü.
Büyük önizleme

Bileşenlerden oluşan bir cephanelik oluşturmak, tümü ortak bir markayı paylaşan önemli bir web sitesi portföyüne sahip olan Google gibi şirketler için özellikle yararlıdır. Daha büyük şirketler, kullanıcı arabirimlerini şekillendirilebilir widget'lara kodlayarak hem geliştirme süresini hızlandırabilir hem de projeler arasında hem görsel hem de kullanıcı etkileşimi tasarımında tutarlılık sağlayabilir. Son birkaç yılda stil kılavuzlarına ve desen kitaplıklarına ilgi arttı. Birden fazla takıma yayılmış birden fazla geliştirici ve tasarımcı göz önüne alındığında, büyük şirketler tutarlılık elde etmeye çalışır. Basit renk örneklerinden daha iyisini yapabiliriz. İhtiyacımız olan, kolayca dağıtılabilir kod .

Kodu Paylaşma ve Yeniden Kullanma

Kodu manuel olarak kopyalayıp yapıştırmak zahmetsizdir. Ancak bu kodu güncel tutmak bir bakım kabusu. Bu nedenle birçok geliştirici, kodu projeler arasında yeniden kullanmak için bir paket yöneticisine güvenir. Adına rağmen, Düğüm Paket Yöneticisi, ön uç paket yönetimi için rakipsiz bir platform haline geldi. Şu anda NPM kayıt defterinde 700.000'den fazla paket var ve her ay milyarlarca paket indiriliyor. package.json dosyasına sahip herhangi bir klasör, paylaşılabilir bir paket olarak NPM'ye yüklenebilir. NPM öncelikle JavaScript ile ilişkilendirilirken, bir paket CSS ve işaretleme içerebilir. NPM, kodu yeniden kullanmayı ve daha da önemlisi güncellemeyi kolaylaştırır. Kodu sayısız yerde değiştirmek zorunda kalmak yerine, kodu yalnızca pakette değiştirirsiniz.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

İşaretleme Sorunu

Sass ve Javascript, import deyimlerinin kullanımıyla kolayca taşınabilir. Şablonlama dilleri, HTML'ye aynı yeteneği verir; şablonlar, HTML'nin diğer parçalarını kısmi olarak içe aktarabilir. Altbilginiz için işaretlemeyi örneğin yalnızca bir kez yazabilir, ardından diğer şablonlara dahil edebilirsiniz. Çok sayıda şablonlama dilinin var olduğunu söylemek yetersiz kalır. Kendinizi yalnızca bir tanesine bağlamak, kodunuzun potansiyel yeniden kullanılabilirliğini ciddi şekilde sınırlar. Alternatif, işaretlemeyi kopyalayıp yapıştırmak ve NPM'yi yalnızca stiller ve javascript için kullanmaktır.

Bu, Financial Times'ın Origami bileşen kitaplığıyla benimsediği yaklaşımdır. Konuşmasında “Bootstrap gibi Yapamaz mısın?” Alice Bartlett, "insanların projelerine şablon eklemelerine izin vermenin iyi bir yolu olmadığı" sonucuna vardı. Lonely Planet'te bir bileşen kitaplığı sürdürme deneyiminden bahseden Ian Feather, bu yaklaşımla ilgili sorunları yineledi:

“Bu kodu bir kez kopyaladıklarında, esasen süresiz olarak korunması gereken bir sürümü kesiyorlar. Çalışan bir bileşen için işaretlemeyi kopyaladıklarında, o noktada CSS'nin bir anlık görüntüsüne örtülü bir bağlantısı vardı. Daha sonra şablonu güncellerseniz veya CSS'yi yeniden düzenlerseniz, sitenize dağılmış şablonun tüm sürümlerini güncellemeniz gerekir."

Çözüm: Web Bileşenleri

Web bileşenleri, JavaScript'te işaretleme tanımlayarak bu sorunu çözer. Bir bileşenin yazarı, işaretlemeyi, CSS'yi ve Javascript'i değiştirmekte özgürdür. Bileşenin tüketicisi, kodu elle değiştiren bir projede gezinmeye gerek kalmadan bu yükseltmelerden yararlanabilir. Proje genelindeki en son değişikliklerle senkronizasyon, terminal aracılığıyla kısa bir npm update ile sağlanabilir. Yalnızca bileşenin adı ve API'sinin tutarlı kalması gerekir.

Bir web bileşenini kurmak, bir terminale npm install component-name yazmak kadar basittir. Javascript bir import ifadesi ile dahil edilebilir:

 <script type="module"> import './node_modules/component-name/index.js'; </script>

Ardından, bileşeni işaretlemenizin herhangi bir yerinde kullanabilirsiniz. İşte metni panoya kopyalayan basit bir örnek bileşen.

CodePen'de CSS GRID (@cssgrid) tarafından hazırlanan Pen Simple web bileşeni demosuna bakın.

CodePen'de CSS GRID (@cssgrid) tarafından hazırlanan Pen Simple web bileşeni demosuna bakın.

Ön uç geliştirmeye yönelik bileşen merkezli bir yaklaşım, Facebook'un React çerçevesi tarafından başlatılan her yerde yaygın hale geldi. Kaçınılmaz olarak, modern ön uç iş akışlarındaki çerçevelerin yaygınlığı göz önüne alındığında, birçok şirket kendi seçtikleri çerçeveyi kullanarak bileşen kitaplıkları oluşturmuştur. Bu bileşenler yalnızca söz konusu çerçeve içinde yeniden kullanılabilir.

IBM'in Karbon Tasarım Sisteminden bir bileşen
IBM'in Karbon Tasarım Sisteminden bir bileşen. Yalnızca React uygulamalarında kullanım içindir. React'te yerleşik bileşen kitaplıklarının diğer önemli örnekleri arasında Atlassian'dan Atlaskit ve Shopify'dan Polaris bulunur. (Büyük önizleme)

Büyük bir şirketin tek tip bir ön yüze sahip olması ve bir çerçeveden diğerine yeniden platform oluşturma nadir değildir. Çerçeveler gelir ve gider. Projeler arasında maksimum miktarda potansiyel yeniden kullanımı etkinleştirmek için çerçeveden bağımsız bileşenlere ihtiyacımız var.

Belirli javascript çerçeveleri için özel olarak oluşturulmuş aynı şeyi yapan bileşenleri gösteren npmjs.com'dan bir ekran görüntüsü.
Bileşenleri npmjs.com üzerinden aramak, parçalanmış bir Javascript ekosistemini ortaya çıkarır. (Büyük önizleme)
Çerçevelerin zaman içindeki popülerliğini gösteren bir grafik. Ember, Knockout ve Backbone popülaritesi düştü ve yerini daha yeni tekliflere bıraktı.
Çerçevelerin zaman içinde sürekli değişen popülaritesi. (Büyük önizleme)
"Yıllar içinde Dojo, Mootools, Prototype, jQuery, Backbone, Thorax ve React'i kullanarak web uygulamaları geliştirdim... Yanımda köle olarak kullandığım o öldürücü Dojo bileşenini React'ime getirebilmeyi çok isterdim. bugünün uygulaması.”

— Dion Almaer, Mühendislik Direktörü, Google

Bir web bileşeni hakkında konuştuğumuzda, özel bir öğenin gölge DOM ile birleşiminden bahsediyoruz. Özel Öğeler ve gölge DOM, hem W3C DOM belirtiminin hem de WHATWG DOM Standardının bir parçasıdır - yani web bileşenleri bir web standardıdır . Özel öğeler ve gölge DOM nihayet bu yıl çapraz tarayıcı desteği sağlayacak şekilde ayarlandı. Yerel web platformunun standart bir parçasını kullanarak, bileşenlerimizin hızlı hareket eden ön uç yeniden yapılandırma ve mimari yeniden düşünme döngüsünde hayatta kalmasını sağlıyoruz. Web bileşenleri, herhangi bir şablonlama dili ve herhangi bir ön uç çerçeve ile kullanılabilir - gerçekten çapraz uyumlu ve birlikte çalışabilirler. Bir Wordpress blogundan tek sayfalık bir uygulamaya kadar her yerde kullanılabilirler.

Rob Dodson tarafından hazırlanan Custom Elements Everywhere projesi, web bileşenlerinin çeşitli istemci tarafı Javascript çerçeveleriyle birlikte çalışabilirliğini belgeliyor.
Rob Dodson tarafından hazırlanan Custom Elements Everywhere projesi, web bileşenlerinin çeşitli istemci tarafı Javascript çerçeveleriyle birlikte çalışabilirliğini belgeliyor. Buradaki aykırı değer olan React, umarım bu sorunları React 17 ile çözecektir. (Geniş önizleme)

Web Bileşeni Yapmak

Özel Bir Öğe Tanımlama

Etiket adları oluşturmak ve içeriklerinin sayfada görünmesini sağlamak her zaman mümkün olmuştur.

 <made-up-tag>Hello World!</made-up-tag>

HTML hataya dayanıklı olacak şekilde tasarlanmıştır. Geçerli bir HTML öğesi olmasa da yukarıdakiler oluşturulacaktır. Bunu yapmak için hiçbir zaman iyi bir neden olmadı - standart etiketlerden sapmak geleneksel olarak kötü bir uygulama olmuştur. Ancak özel öğe API'sini kullanarak yeni bir etiket tanımlayarak HTML'yi yerleşik işlevselliğe sahip yeniden kullanılabilir öğelerle zenginleştirebiliriz. Özel bir öğe oluşturmak, HTMLElement bir bileşen oluşturmaya çok benzer - ancak burada HTMLElement öğesini genişletiyoruz.

 class ExpandableBox extends HTMLElement { constructor() { super() } }

super() için parametresiz bir çağrı, yapıcıdaki ilk ifade olmalıdır. Yapıcı, başlangıç ​​durumunu ve varsayılan değerleri ayarlamak ve herhangi bir olay dinleyicisini ayarlamak için kullanılmalıdır. HTML etiketi ve sınıfa karşılık gelen öğeler için bir adla yeni bir özel öğenin tanımlanması gerekir:

 customElements.define('expandable-box', ExpandableBox)

Sınıf adlarını büyük harf kullanmak için bir kuraldır. Bununla birlikte, HTML etiketinin sözdizimi bir kuraldan daha fazlasıdır. Tarayıcılar yeni bir HTML öğesi uygulamak isterse ve buna genişletilebilir kutu adını vermek isterse ne olur? Ad çakışmalarını önlemek için yeni standartlaştırılmış HTML etiketleri tire içermeyecektir. Buna karşılık, özel öğelerin adları bir tire içermelidir.

 customElements.define('whatever', Whatever) // invalid customElements.define('what-ever', Whatever) // valid

Özel Öğe Yaşam Döngüsü

API, özel bir öğenin yaşam döngüsündeki belirli olaylara yanıt olarak otomatik olarak çağrılacak sınıf içinde tanımlanabilen işlevler olan dört özel öğe tepkisi sunar.

Özel öğe DOM'a eklendiğinde connectCallback çalıştırılır.

 connectedCallback() { console.log("custom element is on the page!") }

Bu, Javascript ile bir öğe eklemeyi içerir:

 document.body.appendChild(document.createElement("expandable-box")) //“custom element is on the page”

ayrıca öğeyi bir HTML etiketiyle sayfaya dahil etmenin yanı sıra:

 <expandable-box></expandable-box> // "custom element is on the page"

Kaynak getirmeyi veya oluşturmayı içeren herhangi bir çalışma burada olmalıdır.

BağlantısızCallback , özel öğe DOM'den kaldırıldığında çalıştırılır.

 disconnectedCallback() { console.log("element has been removed") } document.querySelector("expandable-box").remove() //"element has been removed"

benimsenenCallback, özel öğe yeni bir belgeye adoptedCallback çalıştırılır. Muhtemelen bunun için çok sık endişelenmenize gerek yok.

attributeChangedCallback , bir nitelik eklendiğinde, değiştirildiğinde veya kaldırıldığında çalıştırılır. Disable veya src gibi standartlaştırılmış yerel özniteliklerin yanı sıra oluşturduğumuz özel özniteliklerdeki değişiklikleri dinlemek için kullanılabilir. Bu, kullanıcı dostu bir API oluşturulmasını sağladığı için özel öğelerin en güçlü yönlerinden biridir.

Özel Öğe Nitelikleri

Çok sayıda HTML özelliği vardır. Herhangi bir öznitelik değiştirildiğinde tarayıcının attributeChangedCallback arayarak zaman kaybetmemesi için, dinlemek istediğimiz öznitelik değişikliklerinin bir listesini sağlamamız gerekir. Bu örnek için yalnızca biriyle ilgileniyoruz.

 static get observedAttributes() { return ['expanded'] }

Bu nedenle, şimdi attributeChangedCallback , yalnızca özel öğedeki genişletilmiş özelliğin değerini değiştirdiğimizde çağrılacak, çünkü bu, listelediğimiz tek niteliktir.

HTML öznitelikleri karşılık gelen değerlere sahip olabilir (think href, src, alt, value vb), diğerleri ise doğru veya yanlıştır (örneğin , devre dışı, seçili, gerekli ). Karşılık gelen bir değere sahip bir öznitelik için, özel öğenin sınıf tanımına aşağıdakini ekleriz.

 get yourCustomAttributeName() { return this.getAttribute('yourCustomAttributeName'); } set yourCustomAttributeName(newValue) { this.setAttribute('yourCustomAttributeName', newValue); }

Örnek öğemiz için öznitelik ya doğru ya da yanlış olacaktır, bu nedenle alıcı ve ayarlayıcıyı tanımlamak biraz farklıdır.

 get expanded() { return this.hasAttribute('expanded') } // the second argument for setAttribute is mandatory, so we'll use an empty string set expanded(val) { if (val) { this.setAttribute('expanded', ''); } else { this.removeAttribute('expanded') } }

Artık ortak attributeChangedCallback ile ilgilenildiğine göre, featureChangedCallback'i kullanabiliriz.

 attributeChangedCallback(name, oldval, newval) { console.log(`the ${name} attribute has changed from ${oldval} to ${newval}!!`); // do something every time the attribute changes }

Geleneksel olarak, bir Javascript bileşenini yapılandırmak, argümanların bir init işlevine iletilmesini gerektirirdi. attributeChangedCallback kullanılarak, yalnızca biçimlendirme ile yapılandırılabilen özel bir öğe yapmak mümkündür.

Gölge DOM ve özel öğeler ayrı ayrı kullanılabilir ve özel öğeleri kendi başlarına yararlı bulabilirsiniz. Gölge DOM'den farklı olarak, çoklu doldurulabilirler. Ancak, iki özellik birlikte iyi çalışır.

Shadow DOM ile İşaretleme ve Stil Ekleme

Şimdiye kadar, özel bir öğenin davranışını ele aldık. Bununla birlikte, biçimlendirme ve stiller ile ilgili olarak, özel öğemiz, stillendirilmemiş boş bir <span> ile eşdeğerdir. Bileşenin bir parçası olarak HTML ve CSS'yi kapsüllemek için bir gölge DOM eklememiz gerekiyor. Bunu yapıcı işlevi içinde yapmak en iyisidir.

 class FancyComponent extends HTMLElement { constructor() { super() var shadowRoot = this.attachShadow({mode: 'open'}) shadowRoot.innerHTML = `<h2>hello world!</h2>` }

Modun ne anlama geldiğini anlama konusunda endişelenmeyin - onun ortak özelliklerini dahil etmeniz gerekir, ancak hemen hemen her zaman open isteyeceksiniz. Bu basit örnek bileşen sadece "merhaba dünya" metnini oluşturacaktır. Diğer HTML öğelerinin çoğu gibi, özel bir öğenin çocukları olabilir - ancak varsayılan olarak değil. Şimdiye kadar tanımladığımız yukarıdaki özel öğe ekrana herhangi bir çocuk getirmeyecektir. Etiketler arasında herhangi bir içeriği görüntülemek için bir slot öğesi kullanmamız gerekir.

 shadowRoot.innerHTML = ` <h2>hello world!</h2> <slot></slot> `

Bileşene biraz CSS uygulamak için bir stil etiketi kullanabiliriz.

 shadowRoot.innerHTML = `<style> p { color: red; } </style> <h2>hello world!</h2> <slot>some default content</slot>`

Bu stiller yalnızca bileşene uygulanacaktır, bu nedenle stiller sayfanın başka hiçbir şeyini etkilemeden öğe seçicileri kullanmakta özgürüz. Bu, CSS yazmayı basitleştirir ve BEM gibi adlandırma kurallarını gereksiz kılar.

NPM'de Bir Bileşen Yayınlama

NPM paketleri komut satırı aracılığıyla yayınlanır. Bir terminal penceresi açın ve yeniden kullanılabilir bir pakete dönüştürmek istediğiniz dizine gidin. Ardından terminale aşağıdaki komutları yazın:

  1. Projenizde zaten bir package.json yoksa, npm init bir tane oluşturmanız için size yol gösterecektir.
  2. npm adduser , makinenizi NPM hesabınıza bağlar. Önceden var olan bir hesabınız yoksa, sizin için yeni bir hesap oluşturacaktır.
  3. npm publish
NPM paketleri komut satırı aracılığıyla yayınlanır
Büyük önizleme

Her şey yolunda giderse, artık NPM kayıt defterinde, kendi projelerinizde kurulmaya ve kullanılmaya hazır ve dünya ile paylaşılmaya hazır bir bileşeniniz var.

NPM kayıt defterindeki, kendi projelerinizde kurulmaya ve kullanılmaya hazır bir bileşen örneği.
Büyük önizleme

Web bileşenleri API'si mükemmel değil. Özel öğeler şu anda form gönderimlerine veri ekleyemiyor. Aşamalı geliştirme hikayesi harika değil. Erişilebilirlikle başa çıkmak, olması gerektiği kadar kolay değildir.

İlk olarak 2011'de duyurulmasına rağmen, tarayıcı desteği hala evrensel değildir. Firefox desteği bu yıl içinde sona erecek. Bununla birlikte, bazı yüksek profilli web siteleri (Youtube gibi) zaten bunları kullanıyor. Mevcut eksikliklerine rağmen, evrensel olarak paylaşılabilir bileşenler için tek seçenek bunlar ve gelecekte sunduklarına heyecan verici eklemeler bekleyebiliriz.