10 poin oleh GN⁺ 2025-04-23 | 3 komentar | Bagikan ke WhatsApp
  • Writing JavaScript Views the Hard Way : artikel yang menjelaskan cara membangun view hanya dengan JavaScript murni tanpa framework
  • Melalui pendekatan imperatif langsung, pendekatan ini memberikan performa, kemudahan perawatan, dan portabilitas
  • Pembaruan state dan pembaruan DOM dipisahkan dengan jelas, serta mengikuti aturan penamaan yang ketat dan pola struktural sesuai perannya
  • Pendekatan ini mudah di-debug, menjamin kompatibilitas dengan semua browser, dan memiliki keunggulan besar berupa 0 dependencies
  • Meski bisa terasa sulit bagi pemula, mempelajarinya memberi pemahaman mendalam tentang cara kerja sistem yang sebenarnya

Menulis view JavaScript dengan 'Hard Way'

Apa ini?

  • Pendekatan ini adalah pola untuk menyusun view hanya dengan JavaScript tanpa framework seperti React, Vue, lit-html
  • Ini bukan library atau alat tertentu, melainkan pola penulisan kode itu sendiri, yang membantu mencegah masalah spaghetti code
  • Dengan menggunakan pendekatan imperatif langsung, abstraksi dikurangi dan intuisi ditingkatkan

Kelebihan dibanding framework

  • Performa: karena berupa kode imperatif, ia berjalan tanpa komputasi yang tidak perlu dan cocok untuk hot path maupun cold path
  • 0 dependencies: bebas dari masalah upgrade library atau kompatibilitas
  • Portabilitas: kode yang ditulis dapat dipindahkan ke framework mana pun
  • Kemudahan perawatan: struktur bagian yang jelas dan aturan penamaan memudahkan menemukan lokasi kode
  • Dukungan browser: kompatibel dengan sebagian besar browser mulai IE9 ke atas, dan bahkan IE6 dapat didukung dengan beberapa penyesuaian
  • Kemudahan debugging: memberikan stack trace yang dangkal tanpa lapisan perantara
  • Struktur fungsional: meski bukan immutable, semua komponen disusun berbasis fungsi

Penjelasan struktur

Struktur keseluruhan

  • Terdiri dari fungsi templateclone()init()
  • Fungsi init() membuat satu instance view yang mencakup variabel state, referensi DOM, fungsi update, event listener, dan sebagainya

Contoh struktur kode (Hello World)

const template = document.createElement('template');  
template.innerHTML = `<div>Hello <span id="name">world</span>!</div>`;  
  
function clone() {  
  return document.importNode(template.content, true);  
}  
  
function init() {  
  let frag = clone();  
  let nameNode = frag.querySelector('#name');  
  let name;  
  
  function setNameNode(value) {  
    nameNode.textContent = value;  
  }  
  
  function setName(value) {  
    if(name !== value) {  
      name = value;  
      setNameNode(value);  
    }  
  }  
  
  function update(data = {}) {  
    if(data.name) setName(data.name);  
    return frag;  
  }  
  
  return update;  
}  

Susunan di dalam fungsi init()

1. Variabel DOM

  • frag adalah potongan template yang dibuat dari clone()
  • Elemen di dalamnya direferensikan dengan querySelector(), dan nama variabel menggunakan bentuk fooNode

2. DOM view

  • Bagian yang memuat view lain (sub-view yang dapat digunakan ulang)
  • Contoh:
let updateChildView = childView();  
  • Fungsi pembaruan view diberi nama dalam bentuk updateFoo

3. Variabel state

  • Nilai data yang dapat berubah di dalam view
  • Untuk membuat pembaruan DOM efisien, perubahan DOM hanya dilakukan saat diperlukan dengan membandingkan nilai saat ini

4. Fungsi pembaruan DOM

  • Digunakan saat mengubah status elemen DOM
  • Contoh:
function setNameNode(value) {  
  nameNode.textContent = value;  
}  
  • Manipulasi DOM wajib dilakukan hanya di dalam fungsi ini

5. Fungsi pembaruan state

  • Mencakup logika perubahan state dan penerapannya ke DOM
  • Nilai yang tidak berubah diabaikan untuk mencegah perubahan DOM yang tidak perlu
  • Contoh:
function setName(value) {  
  if(name !== value) {  
    name = value;  
    setNameNode(value);  
  }  
}  

Fungsi template dan clone()

template

  • Membuat struktur HTML statis dengan elemen <template>
  • Tidak langsung dimasukkan ke DOM, melainkan disalin lewat clone

clone()

  • Menggandakan dengan document.importNode(template.content, true)
  • Jika perlu, elemen root dapat dikembalikan menggunakan .firstElementChild

Cara interaksi

Aliran data induk → anak

  • Induk memanggil init() milik anak untuk mendapatkan fungsi update, lalu memanggilnya dalam bentuk update({ name: 'foo' })

Penyebaran data berbasis event

  • Secara default mengikuti model props down, events up
  • View bawahan berkomunikasi dengan mengirim event ke atas

Perbandingan dengan React

  • constructor() (React)init() (Hard Way)
    • Bertanggung jawab atas pengaturan awal komponen
  • render() (React)update(data) (Hard Way)
    • Berperan dalam menyegarkan tampilan dan memperbarui UI
  • this.setState() (React)setX(value) (Hard Way)
    • Digantikan oleh cara mengatur nilai state secara langsung
  • props (React)nilai yang dikirim melalui update(data) (Hard Way)
    • Cara menangani data yang diteruskan dari komponen induk
  • JSX / Virtual DOM (React)template HTML + DOM API (Hard Way)
    • Menggunakan template dan manipulasi DOM manual alih-alih UI deklaratif

Kesimpulan

  • Dibanding framework yang sudah familier, pendekatan ini memang memiliki hambatan awal yang lebih tinggi, tetapi memiliki kekuatan berikut:
    • Optimisasi performa
    • Kontrol penuh
    • Pemahaman mendalam melalui proses belajar
  • Dengan pemisahan fungsi berdasarkan peran dan aturan penamaan, pendekatan ini memungkinkan penyusunan UI yang tetap mudah dirawat tanpa framework

Kompatibilitas

  • Contoh terbaru menggunakan API untuk browser modern, tetapi bahkan hingga IE9 ke bawah pun dapat didukung melalui pengganti berbasis fungsi
  • Dapat diperluas hingga IE6 dengan menggunakan pendekatan meneruskan fungsi lewat props alih-alih event

3 komentar

 
wfedev 2025-04-24

Pada akhirnya kembali ke web component..

 
ahwjdekf 2025-04-23

Selamat. Satu lagi framework js telah lahir.

 
GN⁺ 2025-04-23
Komentar Hacker News
  • Ini mungkin bidah bagi banyak developer JS, tetapi saya menganggap variabel state sebagai anti-pattern

    • Saat menggunakan web components, alih-alih menambahkan variabel state untuk tipe variabel yang 'datar', saya menggunakan value/textContent/checked pada elemen DOM sebagai satu-satunya sumber kebenaran
    • Saya menambahkan setter dan getter bila diperlukan
    • Dengan jumlah kode yang lebih sedikit pun, banyak hal tetap berjalan dengan benar secara alami
    • Menggunakan WebComponents memisahkan objek dan template HTML yang berdekatan, sehingga pemecahannya bukan menjadi kode spaghetti melainkan sesuatu yang lebih tersegmentasi seperti fusilli atau makaroni
  • Dokumentasinya mengatakan pendekatan ini sangat mudah dirawat, tetapi saya tidak setuju

    • Design pattern ini hanya bertumpu pada konvensi
    • Saat banyak developer bekerja bersamaan pada aplikasi yang kompleks, kemungkinan besar setidaknya ada satu orang yang akan menyimpang dari konvensi
    • Framework UI berbasis kelas seperti UIKit di iOS memaksa semua developer memakai satu set API standar, sehingga kodenya lebih dapat diprediksi dan lebih mudah dirawat
  • Belakangan ini saya menulis aplikasi dengan TypeScript 'vanilla' murni bersama vite, dan makin mempertanyakan praktik 'terbaik' frontend

    • Saya belum bisa menyimpulkan soal skalabilitas, tetapi dari sisi performa ada keuntungan besar
    • Ini menyenangkan, saya belajar banyak, debugging jadi sederhana, dan arsitekturnya mudah dipahami
    • Yang paling saya rindukan adalah templating
  • Pendekatan ini mengingatkan saya pada library backbone js yang lama

    • Ada juga repositori GitHub yang berisi contoh pola MVC yang diadaptasi ke platform web
  • Saya baru-baru ini memikirkan sesuatu yang mirip, tetapi tidak menggunakan elemen template

    • Saya memakai fungsi dan template literal untuk mengembalikan string, lalu memasukkannya ke innerHTML elemen yang ada atau membuat elemen div baru untuk menaruhnya
    • Fungsi-fungsinya jadi saling bertingkat sehingga sulit disusun dengan cara yang masuk akal
  • Kode ini terlihat persis seperti kode pembaruan manual yang ingin digantikan oleh library view reaktif

  • Saya sudah memprogram sekitar 20 tahun tetapi belum pernah benar-benar terbiasa dengan framework frontend

    • Saya lebih kuat di backend, jadi menurut saya interaksi terkait keamanan seharusnya lewat server
    • Saya memandang JS sebagai cara menambahkan kemampuan sisi klien di atas fondasi HTML dan CSS yang kokoh
  • Saya menggunakan helper yang mirip dengan React.createElement

    • Ada contoh yang berfungsi dari dashboard server tiruan
  • Saya sedang mengerjakan deja-vu.junglecoder.com sebagai upaya membangun toolkit JS untuk alat berbasis HTML

    • Binding data reaktif/dua arah yang layak masih belum saya pecahkan, tetapi grab/patch lumayan bagus
    • Cara penggunaan template membuat pemindahan sebagian template menjadi sangat mudah
  • Di pekerjaan resmi pertama saya setelah lulus kuliah, saya membuat versi web dari software Delphi

    • Timnya sudah sedang menulis ulang frontend untuk ketiga kalinya, dan kami harus mengganti framework
    • Saya berpendapat bahwa kami seharusnya menulis framework sendiri, tetapi tim tidak menyukai usulan saya
    • Setelah itu saya pergi karena mendapat tawaran yang lebih baik dari perusahaan lain
    • Sejak itu saya mencoba framework lain bernama tiny.js, dan sedang memakainya untuk proyek pribadi