Membangun Aplikasi To-Do dengan TypeScript, Webpack, dan browser localStorage
Perkembangan teknologi mengharuskan developer untuk beradaptasi. TIdak hanya beradaptasi, developer pun dituntut untuk “kreatif” dalam memanfaatkan teknologi tersebut. Kombinasi dari teknologi tersebut dapat menciptakan suatu produk. Salah satu bentuk produk yang sederhana yakni aplikasi To-do.
TypeScript
Pada tahun 2012, Microsoft menciptakan sebuah bahasa baru, atau lebih tepatnya “upgrade”-an dari JavaScript. Karakteristik dari TypeScript ini, seperti namanya, yakni static typed. TypeScript mendukung untuk mendeklarasikan tipe data dari suatu variabel, hingga return value sebuah fungsi.
Untuk menjalankan file TypeScript (.ts) diperlukan compiler TypeScript yang dapat dipasang melalui NPM secara global maupun dalam project tertentu. Output dari hasil compile file .ts yakni .js sehingga dapat dikenali dan dieksekusi oleh browser, sebab browser tidak mengenali file .ts. Oleh karena itu, TypeScript dipasang sebagai devDependencies pada suatu project yang berarti bertujuan untuk membantu developer menghindari bug.
Webpack
Teknologi lain yang sangat membantu pengembangan web yakni module bundler, seperti Webpack. Sebelum adanya tool module bundler, berkas-berkas aset seperti stylesheet, script, dan lainnya dimuat secara terpisah. Dengan adanya module bundler, semua aset tersebut dapat dimuat dalam satu file JavaScript saja. Hal ini tentu akan mempercepat pemanggilan aset sehingga akan lebih cepat pula diterima oleh pengguna atau pengunjung web.
LocalStorage
LocalStorage merupakan penyimpanan permanen yang dimiliki oleh browser. Permanen berarti data tidak akan hilang jika window dimuat ulang bahkan saat browser ditutup. Data akan hilang hanya jika dihapus oleh pengguna, salah satunya melalui JavaScript (script).
Prasyarat
Agar dapat mengikuti hands-on code lab ini, setidaknya perlu mengerti dasar dari materi-materi berikut:
- Memahami dasar dari Node.js dan memasangnya pada komputer
- NPM (package manager, bisa juga menggunakan Yarn)
- Memahami TypeScript dasar dan telah memasangnya pada komputer secara global
- Paham JavaScript (ES6+), manipulasi Document Object Model (DOM), dan localStorage pada browser
Inisialisasi Proyek
Buat sebuah folder baru di direktori yang tidak membutuhkan akses admin seperti “C:\Program Files”. Buka terminal atau command prompt yang mengarah pada folder tersebut, kemudian jalankan perintah untuk menginisialisasi proyek Node.js sebab Webpack “berjalan” di atas Node.js.
Ikuti perintah berikutnya seperti menentukan nama proyek, versi, dan sebagainya hingga selesai. Secara otomatis akan dibuat file package.json, dan file package.json ini sebaiknya tidak disunting secara langsung kecuali pada bagian scripts. Untuk sementara, silakan tambahkan property “build” dan “serve” dengan nilainya seperti pada gambar di bawah.
File konfigurasi TypeScript dapat dibuat dengan generate secara otomatis dengan perintah tsc –init dan akan menghasilkan file tsconfig.json yang isinya cukup panjang. Untuk sementara, isi dari file tsconfig.json dapat diabaikan.
Alur Eksekusi Kode Proyek
Sebagai studi kasus dan bahan pembelajaran, aplikasi web yang akan dibangun adalah aplikasi To-do. Secara sederhana, alur eksekusi kode akan berjalan seperti berikut.
Instalasi Dependencies Proyek
Browser tidak mengenal file .ts seperti yang telah disinggung sebelumnya, oleh karena itu perlu diterjemahkan terlebih dahulu ke file JavaScript atau .js. NPM memiliki module untuk menerjemahkan file .ts menjadi .js, yakni ts-loader. Diperlukan juga beberapa dependency lain yang dipasang hanya untuk development saja.
Pastikan terdapat property devDependencies pada package.json setelah proses instalasi selesai.
Konfigurasi tsconfig.json
Konfigurasi TypeScript compiler cukup mudah dilakukan sebab sudah disediakan komentar yang dapat dijadikan sebagai panduan. Pada latihan ini, cukup ubah tiga value dari property yang ada di tsconfig.json.
Perlu dicatat, property target memiliki arti bahwa hasil compile file .ts akan menjadi file .js dengan standar ES6 dan property module dengan value ES2015 bertujuan agar developer dapat menggunakan keyword “import/export” pada project ini. Sedangkan property sourceMap dengan value true merupakan sebuah “property ajaib" bagi developer karena akan memudahkan developer tracing kesalahan saat pengkodean.
Konfigurasi file webpack.config.js
Salah satu komponen atau file penting yang sangat menentukan bahwa project tersebut merupakan “project webpack” atau bukan yakni adanya file konfigurasi webpack. Secara sederhana, segala sesuatu yang dilakukan oleh webpack beserta dependencies pendukungnya akan melihat file konfigurasi webpack terlebih dahulu.
Buat file webpack.config.js pada project root directory dengan isi sebagai berikut.
Entry point project ini yakni terdapat pada direktori src dengan nama file index.ts. Kemudian load module yang telah dipasang, yakni ts-loader (untuk load file .ts) serta style-loader dan css-loader (untuk load file stylesheet). Terdapat property rule pada module, yakni untuk mengetes file-file yang akan dieksekusi. Khusus untuk penggunaan ts-loader, di-set hanya akan mengeksekusi file berekstensi .ts yang ada pada direktori ./src saja. Berbeda dengan file stylesheet yang dapat dieksekusi di mana saja selama masih dapat satu project.
Agar dapat Webpack mengetahui ekstensi file yang akan di-load, tambah property resolve dengan value berupa object yang berisi property extensions bertipe array seperti pada gambar di bawah. Hal ini dilakukan agar developer dapat menggunakan keyword “import/export”. Ekstensi file .js ditambahkan untuk berjaga-jaga jika dikemudian hari dibutuhkan untuk import file berekstensi .js.
Setelah webpack mengetahui “tempat-tempat yang harus dikunjungi”, ia harus mengetahui juga “tujuan akhir” dari perjalanan tersebut, yakni tempat menyimpan file output atau bundle. Pada project ini, file output akan disimpan pada direktori public dengan nama bundle.js.
Agar mempercepat proses development, tambahkan juga property devServer agar fitur hot reload dari webpack dapat digunakan. Perhatikan juga untuk static directory nya sesuaikan dengan output path.
Buat file index.html pada folder public yang dihubungkan dengan script bundle.js
Buat juga file css/style.css dengan isi seperti di sini
Berikut struktur project yang telah dibuat sejauh ini.
Silakan coba test dengan cara menjalankan perintah console pada file index.ts lalu jalankan perintah berikut dan buka http://localhost:400.
Pastikan terdapat log pada browser console. Jika tidak, silakan dicek kembali. Kemungkinan ada konfigurasi yang terlewat atau tidak sesuai. Tampilan awal akan seperti gambar di bawah.
Membuat Component To Do Item
Component yang dibuat merupakan sebuah fungsi yang menerima parameter berupa object yang wajib memiliki property todo bertipe string dan timestamps bertipe number. Return value dari fungsi ini yakni sebuah string yang akan di-inject pada HTML menjadi child dari component div dengan kelas ‘todo-list’.
Sesuai dengan spesifikasi parameter fungsi toDoItemGenerator, buat interface yang langsung diekspor pada src/interfaces/index.ts seperti berikut.
Seleksi Statis DOM
Statis DOM yang dimaksud di sini yakni DOM yang tidak di-generate oleh JavaScript atau lebih tepatnya fungsi toDoItemGenerator. Seleksi DOM ini dilakukan pada module atau file terpisah serta diekspor sehingga mudah untuk dipanggil dan dapat merampingkan penulisan kode.
Membuat Fitur Tambah To-do
To do item akan disimpan ke localstorage dengan key “latihan_todo”. Berikut alur insert item baru.
Mari kita terapkan flowchart di atas!
Import dahulu elemen DOM yang telah diseleksi sebelumnya
Berikan event listener untuk form berupa “submit” agar ketika pengguna menekan enter atau mengeklik tombol tambah, form akan terpelatuk menjalankan fungsi yang akan dibuat nantinya. Jangan lupa untuk mencegah event bawaan ketika form disubmit, yakni pindah ke halaman lain.
Buat sebuah variable dengan keyword let agar dapat diubah kembali isinya.
Fungsi checkLocalStorage dibuat pada file src/utils/index.ts yang bertujuan untuk mengecek ada atau tidak localStorage dengan key “latihan_todo”. Pengecekan ini akan dilakukan lebih dari satu baik saat membuat fitur tambah, menampilkan data, maupun menghapus item to do. Untuk return value dari fungsi checkLocalStorage yakni sebuah array yang berisi to do item. Deklarasi tipe data return value ini bersifat opsional, namun sangat disarankan karena TypeScript mendukung static typed.
Buat juga fungsi yang digunakan untuk menambah data. Beri nama untuk fungsi tersebut insertToDo yang menerima parameter berupa object dengan interface spesifik, yakni input (input HTML input elemen) dan localJson (array hasil konversi localStorage dengan key “latihan_todo”. Jangan lupa setelah push item baru berupa object dengan key timestamps (key ID unik) dan todo (deskripsi todo) ke localJson set juga localStorage “latihan_todo” dengan localJson (nilai terbaru) yang telah dikonversi menjadi string sebab localStorage hanya dapat diisi oleh tipe data string saja. Tidak ketinggalan, kosongkan kembali value input agar kolom input menjadi kosong kembali.
Panggil fungsi insertToDo di fungsi addEventListener form agar dapat dijalankan. Berikan argument input (HTMl elemen yang telah diseleksi sebelumnya) dan array localJson.
Setelah itu, cek kembali localStorage “latihan_todo” dengan cara menimpa nilai localJson sebelumnya.
Silakan coba menambahkan item kemudian cek localStorage, pastikan ada yang bernama latihan_todo dengan item berupa object yang memiliki dua key, yakni timestamps dan todo.
Sejauh ini, kita telah berhasil menambah item ke localStorage “latihan_todo”. Silakan coba tambah item lain lagi.
Tampilkan To-do ke Layar
Setelah menambahkan data, penting untuk menampilkan “latihan_todo” ke DOM atau layar. Oleh karena itu DOM perlu diperbarui ketika window pertama kali di-load dan ketika ada item baru yang masuk ke “latihan_todo”, juga diperbarui ketika ada item yang dihapus dari “latihan_todo”. Berikut alur untuk update screen.
Untuk menjalankan skenario pertama, yakni window pertama kali dimuat, panggil method atau fungsi yang menempel pada window, yakni onload tanpa menerima parameter apapun. Pada fungsi tersebut, cek “latihan_todo” yang dimasukan ke variabel localJson. Jika panjang dari localJson sama dengan nol, ganti atau timpa inner HTML dari toDoList (elemen yang telah diseleksi sebelumnya, jangan lupa untuk import terlebih dahulu pada entry point index.ts) dengan string ‘Tambahkan item baru!’.
Untuk menangani kasus jika sudah ada item pada “latihan_todo”, buat fungsi updateScreen pada src/utils/index.ts. Fungsi tersebut menerima parameter sebuah object spesifik memiliki nodeList berupa array dari kumpulan object ToDoInterface serta toDoList yang merupakan elemen div HTML yang telah diseleksi sebelumnya. Lakukan iterasi pada nodeList untuk concate string toDoItem yang nantinya akan menggantikan inner HTMl dari toDoList.
Siapkan juga jika ada kasus panjang array “latihan_todo” kurang atau sama dengan 0.
Setelah fungsi updateScreen dibuat, import fungsi tersebut pada entry point dan panggil fungsi updateScreen pada window.onload serta form.addEventListener.
Untuk mengetes, silakan coba refresh halaman tersebut dan tambahkan item baru. Pastikan item-item (yang baru maupun yang lama) muncul pada halaman beranda aplikasi To Do.
Hapus To-do
Menghapus item dari “latihan_todo” cukup tricky sebab kita harus menerapkan prinsip rekursif, yakni fungsi yang memanggil dirinya sendiri. Berikut alur untuk menghapus item dari “latihan_todo”.
Buat fungsi getDeleteButton pada src/utils/index.ts. Lakukan seleksi terhadap button delete. Oleh karena itu, pastikan DOM atau screen merupakan state paling terakhir. Siapkan juga array kosong Bernama newToDo untuk menampung item terbaru setelah dihapus.
Lakukan perulangan terhadap hasil toDoDeleteButton dan cek “latihan_todo” variabel localJson serta berikan tiap-tiap elemen hasil perulangan event listener berupa klik.
Lakukan perulangan forEach terhadap localJson yang dicek. Jika hasil perulangan dari localJson memiliki timestamps yang tidak sama dengan ID dari elemen (button delete), push item tersebut ke array newToDo. Ini berarti item dari localJson yang memiliki key timestamps yang sama dengan ID dari elemen button delete tidak akan dimasukkan ke array newToDo. Array newToDo itu yang kemudian akan menggantikan nilai lama dari “latihan_todo” pada localStorage.
Setelah itu update screen atau DOM dengan nilai “latihan_todo” terbaru.
Karena DOM sudah diperbarui, maka panggil kembali fungsi getDeleteButtonNode agar elemen-elemen button delete diupdate kembali. Jika fungsi getDeleteButtonNode tidak memanggil dirinya sendiri, maka setelah user menghapus salah satu item ia tidak akan bisa menghapus item lainnya sebelum window di-refresh.
Perlu diingat, kita hanya membuat fungsi menghapus item to do, belum menggunakannya. Maka dari itu, panggil dan eksekusi fungsi getDeleteButtonNode pada window.onload dan form.addEventListener di entry point, yakni index.ts. Pastikan panggil getDeleteButtonNode setelah fungsi updateScreen dieksekusi.
Setelah itu, pastikan tombol delete dapat berjalan dengan baik, yakni dapat menghapus item dari “latihan_todo”.
Jika aplikasi tersebut di-deploy ke server. Jalan perintah npm run build dan copy semua file-nya ke server Anda.
Simpulan
Webpack dapat mem-bundle file TypeScript dengan memasang ts-loader pada project Webpack, begitu juga dengan file style (.css). Menggunakan TypeScript mengantarkan developer menulis “dengan aman" karena adanya fitur static typed yang berarti dapat menghindari error dan mempercepat proses development.
Penyimpanan local browser menggunakan localStorage hanya dapat menerima string saja. Oleh karena itu sebelum memasukkan value ke localStorage, tipe data apapun (kecuali string) harus dikonversi ke string terlebih dahulu.
Sekian yang dapat penulis sampaikan. Sampai jumpa!
------
Repository: https://github.com/estotriramdani/typescript-webpack-playground
Demo: https://estotriramdani.github.io/todo-ts-webpack/
Keyword: localstorage, javascript, typescript, webpack, npm, nodejs, css, html