Cawan Suci Komponen yang Dapat Digunakan Kembali: Elemen Kustom, Shadow DOM, dan NPM

Diterbitkan: 2022-03-10
Ringkasan cepat Artikel ini membahas tentang menambah HTML dengan komponen yang memiliki fungsionalitas dan gaya bawaan. Kami juga akan mempelajari cara membuat elemen khusus ini dapat digunakan kembali di seluruh proyek menggunakan NPM.

Bahkan untuk komponen yang paling sederhana, biaya tenaga kerja manusia mungkin signifikan. Tim UX melakukan pengujian kegunaan. Serangkaian pemangku kepentingan harus menandatangani desain.

Pengembang melakukan pengujian AB, audit aksesibilitas, pengujian unit, dan pemeriksaan lintas-browser. Setelah Anda memecahkan masalah, Anda tidak ingin mengulangi upaya itu . Dengan membangun pustaka komponen yang dapat digunakan kembali (daripada membangun semuanya dari awal), kami dapat terus memanfaatkan upaya sebelumnya dan menghindari meninjau kembali tantangan desain dan pengembangan yang sudah terpecahkan.

Tangkapan layar situs web komponen material Google – menampilkan berbagai komponen.
Pratinjau besar

Membangun gudang komponen sangat berguna bagi perusahaan seperti Google yang memiliki portofolio situs web yang cukup besar yang semuanya memiliki merek yang sama. Dengan mengkodifikasi UI mereka menjadi widget yang dapat dikomposisi, perusahaan besar dapat mempercepat waktu pengembangan dan mencapai konsistensi desain visual dan interaksi pengguna di seluruh proyek. Ada peningkatan minat dalam panduan gaya dan perpustakaan pola selama beberapa tahun terakhir. Mengingat banyak pengembang dan desainer tersebar di beberapa tim, perusahaan besar berusaha mencapai konsistensi. Kita bisa melakukan lebih baik daripada swatch warna sederhana. Yang kita butuhkan adalah kode yang mudah didistribusikan .

Berbagi Dan Menggunakan Kembali Kode

Salin dan tempel kode secara manual sangat mudah. Namun, menjaga agar kode itu tetap mutakhir adalah mimpi buruk pemeliharaan. Oleh karena itu, banyak pengembang mengandalkan manajer paket untuk menggunakan kembali kode di seluruh proyek. Terlepas dari namanya, Node Package Manager telah menjadi platform tak tertandingi untuk manajemen paket front-end . Saat ini ada lebih dari 700.000 paket di registri NPM dan miliaran paket diunduh setiap bulan. Folder apa pun dengan file package.json dapat diunggah ke NPM sebagai paket yang dapat dibagikan. Sementara NPM terutama terkait dengan JavaScript, sebuah paket dapat menyertakan CSS dan markup. NPM membuatnya mudah untuk digunakan kembali dan, yang terpenting, memperbarui kode. Daripada perlu mengubah kode di banyak tempat, Anda hanya mengubah kode di package.json.

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

Masalah Markup

Sass dan Javascript mudah dibawa-bawa dengan menggunakan pernyataan impor. Bahasa templating memberi HTML kemampuan yang sama — templat dapat mengimpor fragmen HTML lain dalam bentuk sebagian. Anda dapat menulis markup untuk footer Anda, misalnya, sekali saja, lalu memasukkannya ke dalam template lain. Mengatakan ada banyak bahasa templating akan menjadi pernyataan yang meremehkan. Mengikat diri Anda hanya pada satu sangat membatasi potensi penggunaan kembali kode Anda. Alternatifnya adalah menyalin dan menempel markup dan menggunakan NPM hanya untuk gaya dan javascript.

Ini adalah pendekatan yang diambil oleh Financial Times dengan perpustakaan komponen Origami mereka. Dalam ceramahnya “Can't You Just Make It More like Bootstrap?” Alice Bartlett menyimpulkan "tidak ada cara yang baik untuk membiarkan orang memasukkan template dalam proyek mereka". Berbicara tentang pengalamannya memelihara perpustakaan komponen di Lonely Planet, Ian Feather mengulangi masalah dengan pendekatan ini:

“Begitu mereka menyalin kode itu, mereka pada dasarnya memotong versi yang perlu dipertahankan tanpa batas waktu. Ketika mereka menyalin markup untuk komponen yang berfungsi, itu memiliki tautan implisit ke snapshot CSS pada saat itu. Jika Anda kemudian memperbarui template atau memfaktorkan ulang CSS, Anda perlu memperbarui semua versi template yang tersebar di sekitar situs Anda.”

Solusi: Komponen Web

Komponen web memecahkan masalah ini dengan mendefinisikan markup dalam JavaScript. Penulis komponen bebas untuk mengubah markup, CSS, dan Javascript. Konsumen komponen dapat memperoleh manfaat dari pemutakhiran ini tanpa perlu menelusuri kode pengubah proyek dengan tangan. Menyinkronkan dengan perubahan terbaru di seluruh proyek dapat dicapai dengan npm update singkat melalui terminal. Hanya nama komponen dan API-nya yang harus tetap konsisten.

Memasang komponen web semudah mengetik npm install component-name ke terminal. Javascript dapat disertakan dengan pernyataan impor:

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

Kemudian Anda dapat menggunakan komponen di mana saja di markup Anda. Berikut adalah contoh komponen sederhana yang menyalin teks ke clipboard.

Lihat demo komponen web Pen Simple oleh CSS GRID (@cssgrid) di CodePen.

Lihat demo komponen web Pen Simple oleh CSS GRID (@cssgrid) di CodePen.

Pendekatan komponen-sentris untuk pengembangan front-end telah ada di mana-mana, diantarkan oleh kerangka kerja React Facebook. Tak pelak lagi, mengingat meluasnya kerangka kerja dalam alur kerja front-end modern, sejumlah perusahaan telah membangun pustaka komponen menggunakan kerangka kerja pilihan mereka. Komponen tersebut hanya dapat digunakan kembali dalam kerangka tertentu.

Sebuah komponen dari Sistem Desain Karbon IBM
Sebuah komponen dari Sistem Desain Karbon IBM. Untuk digunakan dalam aplikasi React saja. Contoh signifikan lainnya dari pustaka komponen yang dibangun di React termasuk Atlaskit dari Atlassian dan Polaris dari Shopify. (Pratinjau besar)

Jarang bagi perusahaan yang cukup besar untuk memiliki front-end yang seragam dan mengubah dari satu kerangka kerja ke kerangka kerja lainnya bukanlah hal yang tidak biasa. Kerangka datang dan pergi. Untuk mengaktifkan jumlah maksimum potensi penggunaan kembali di seluruh proyek, kami memerlukan komponen yang agnostik kerangka kerja .

Tangkapan layar dari npmjs.com menunjukkan komponen yang melakukan hal yang sama yang dibuat khusus untuk kerangka kerja javascript tertentu.
Mencari komponen melalui npmjs.com mengungkapkan ekosistem Javascript yang terfragmentasi. (Pratinjau besar)
Grafik yang memetakan popularitas kerangka kerja dari waktu ke waktu. Ember, Knockout, dan Backbone telah jatuh popularitasnya, digantikan oleh penawaran yang lebih baru.
Popularitas kerangka kerja yang terus berubah dari waktu ke waktu. (Pratinjau besar)
“Saya telah membangun aplikasi web menggunakan: Dojo, Mootools, Prototype, jQuery, Backbone, Thorax, dan React selama bertahun-tahun... Saya ingin sekali dapat membawa komponen Dojo pembunuh yang saya kerjakan bersama saya ke React saya. aplikasi hari ini.”

— Dion Almaer, Direktur Teknik, Google

Ketika kita berbicara tentang komponen web, kita berbicara tentang kombinasi elemen kustom dengan shadow DOM. Elemen Kustom dan shadow DOM adalah bagian dari spesifikasi DOM W3C dan Standar DOM WHATWG — artinya komponen web adalah standar web . Elemen kustom dan shadow DOM akhirnya ditetapkan untuk mencapai dukungan lintas-browser tahun ini. Dengan menggunakan bagian standar dari platform web asli, kami memastikan bahwa komponen kami dapat bertahan dari siklus restrukturisasi front-end dan pemikiran ulang arsitektur yang bergerak cepat. Komponen web dapat digunakan dengan bahasa templating apa pun dan kerangka kerja front-end apa pun — mereka benar-benar kompatibel lintas dan dapat dioperasikan. Mereka dapat digunakan di mana saja mulai dari blog Wordpress hingga aplikasi satu halaman.

Proyek Custom Elements Everywhere oleh Rob Dodson mendokumentasikan interoperabilitas komponen web dengan berbagai kerangka kerja Javascript sisi klien.
Proyek Custom Elements Everywhere oleh Rob Dodson mendokumentasikan interoperabilitas komponen web dengan berbagai kerangka kerja Javascript sisi klien. React, outlier di sini, diharapkan akan menyelesaikan masalah ini dengan React 17. (Pratinjau besar)

Membuat Komponen Web

Mendefinisikan Elemen Kustom

Itu selalu mungkin untuk membuat nama tag dan konten mereka muncul di halaman.

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

HTML dirancang untuk toleran terhadap kesalahan. Di atas akan ditampilkan, meskipun itu bukan elemen HTML yang valid. Tidak pernah ada alasan bagus untuk melakukan ini — menyimpang dari tag standar secara tradisional merupakan praktik yang buruk. Namun, dengan mendefinisikan tag baru menggunakan API elemen khusus, kita dapat menambahkan HTML dengan elemen yang dapat digunakan kembali yang memiliki fungsionalitas bawaan. Membuat elemen kustom sangat mirip dengan membuat komponen di React — tetapi di sini kami memperluas HTMLElement .

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

Panggilan tanpa parameter ke super() harus menjadi pernyataan pertama dalam konstruktor. Konstruktor harus digunakan untuk mengatur status awal dan nilai default dan untuk menyiapkan pendengar acara apa pun. Elemen kustom baru perlu didefinisikan dengan nama untuk tag HTML-nya dan elemen kelas yang sesuai:

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

Ini adalah konvensi untuk menggunakan huruf besar pada nama kelas. Sintaks dari tag HTML, bagaimanapun, lebih dari sebuah konvensi. Bagaimana jika browser ingin mengimplementasikan elemen HTML baru dan mereka ingin menyebutnya sebagai kotak yang dapat diperluas? Untuk mencegah tabrakan penamaan, tidak ada tag HTML standar baru yang akan menyertakan tanda hubung. Sebaliknya, nama elemen khusus harus menyertakan tanda hubung.

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

Siklus Hidup Elemen Kustom

API menawarkan empat reaksi elemen kustom — fungsi yang dapat didefinisikan di dalam kelas yang secara otomatis akan dipanggil sebagai respons terhadap peristiwa tertentu dalam siklus hidup elemen kustom.

connectedCallback dijalankan ketika elemen kustom ditambahkan ke DOM.

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

Ini termasuk menambahkan elemen dengan Javascript:

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

serta hanya menyertakan elemen di dalam halaman dengan tag HTML:

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

Pekerjaan apa pun yang melibatkan pengambilan sumber daya atau rendering harus ada di sini.

disconnectedCallback dijalankan ketika elemen khusus dihapus dari DOM.

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

adoptedCallback dijalankan ketika elemen kustom diadopsi ke dalam dokumen baru. Anda mungkin tidak perlu terlalu sering mengkhawatirkan hal ini.

attributeChangedCallback dijalankan ketika atribut ditambahkan, diubah, atau dihapus. Itu dapat digunakan untuk mendengarkan perubahan pada atribut asli standar seperti disabled atau src , serta atribut khusus apa pun yang kami buat. Ini adalah salah satu aspek paling kuat dari elemen kustom karena memungkinkan pembuatan API yang ramah pengguna.

Atribut Elemen Kustom

Ada banyak sekali atribut HTML. Agar browser tidak membuang waktu memanggil atributChangedCallback kita ketika ada attributeChangedCallback yang diubah, kita perlu memberikan daftar perubahan atribut yang ingin kita dengarkan. Untuk contoh ini, kami hanya tertarik pada satu.

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

Jadi sekarang attributeChangedCallback kita hanya akan dipanggil saat kita mengubah nilai atribut yang diperluas pada elemen kustom, karena ini adalah satu-satunya atribut yang telah kita daftarkan.

Atribut HTML dapat memiliki nilai yang sesuai (pikirkan href, src, alt, nilai dll) sementara yang lain benar atau salah (misalnya dinonaktifkan, dipilih, diperlukan ). Untuk atribut dengan nilai yang sesuai, kami akan menyertakan yang berikut ini dalam definisi kelas elemen kustom.

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

Untuk elemen contoh kita, atributnya akan benar atau salah, jadi mendefinisikan pengambil dan penyetel sedikit berbeda.

 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') } }

Sekarang boilerplate telah ditangani, kita dapat menggunakan attributeChangedCallback .

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

Secara tradisional, mengonfigurasi komponen Javascript akan melibatkan melewatkan argumen ke fungsi init . Dengan memanfaatkan attributeChangedCallback , dimungkinkan untuk membuat elemen khusus yang dapat dikonfigurasi hanya dengan markup.

Shadow DOM dan elemen kustom dapat digunakan secara terpisah, dan Anda mungkin menemukan elemen kustom berguna dengan sendirinya. Tidak seperti shadow DOM, mereka dapat di-polyfill. Namun, kedua spesifikasi bekerja dengan baik dalam hubungannya.

Melampirkan Markup Dan Gaya Dengan Shadow DOM

Sejauh ini, kami telah menangani perilaku elemen kustom. Namun, sehubungan dengan markup dan gaya, elemen kustom kami setara dengan <span> kosong tanpa gaya. Untuk merangkum HTML dan CSS sebagai bagian dari komponen, kita perlu melampirkan shadow DOM. Yang terbaik adalah melakukan ini dalam fungsi konstruktor.

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

Jangan khawatir tentang memahami apa arti mode — boilerplate-nya harus Anda sertakan, tetapi Anda akan selalu ingin open . Komponen contoh sederhana ini hanya akan membuat teks "hello world". Seperti kebanyakan elemen HTML lainnya, elemen kustom dapat memiliki turunan — tetapi tidak secara default. Sejauh ini elemen kustom di atas yang telah kita definisikan tidak akan merender anak-anak ke layar. Untuk menampilkan konten apa pun di antara tag, kita perlu menggunakan elemen slot .

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

Kita dapat menggunakan tag gaya untuk menerapkan beberapa CSS ke komponen.

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

Gaya ini hanya akan berlaku untuk komponen, jadi kita bebas menggunakan pemilih elemen tanpa gaya memengaruhi hal lain di halaman. Ini menyederhanakan penulisan CSS, membuat konvensi penamaan seperti BEM tidak diperlukan.

Menerbitkan Komponen Di NPM

Paket NPM diterbitkan melalui baris perintah. Buka jendela terminal dan pindah ke direktori yang ingin Anda ubah menjadi paket yang dapat digunakan kembali. Kemudian ketik perintah berikut ke terminal:

  1. Jika proyek Anda belum memiliki package.json, npm init akan memandu Anda untuk membuatnya.
  2. npm adduser menautkan mesin Anda ke akun NPM Anda. Jika Anda tidak memiliki akun yang sudah ada sebelumnya, itu akan membuat yang baru untuk Anda.
  3. npm publish
Paket NPM diterbitkan melalui baris perintah
Pratinjau besar

Jika semuanya berjalan dengan baik, Anda sekarang memiliki komponen di registri NPM, siap untuk diinstal dan digunakan dalam proyek Anda sendiri — dan dibagikan kepada dunia.

Contoh komponen dalam registri NPM, siap dipasang dan digunakan dalam proyek Anda sendiri.
Pratinjau besar

API komponen web tidak sempurna. Elemen kustom saat ini tidak dapat menyertakan data dalam pengiriman formulir. Cerita peningkatan progresif tidak bagus. Berurusan dengan aksesibilitas tidak semudah yang seharusnya.

Meskipun awalnya diumumkan pada tahun 2011, dukungan browser masih belum universal. Dukungan Firefox akan jatuh tempo akhir tahun ini. Namun demikian, beberapa situs web terkenal (seperti Youtube) sudah memanfaatkannya. Terlepas dari kekurangannya saat ini, untuk komponen yang dapat dibagikan secara universal , mereka adalah pilihan tunggal dan di masa depan kita dapat mengharapkan tambahan yang menarik untuk apa yang mereka tawarkan.