App shell adalah HTML, CSS, dan JavaScript minimal yang mendukung antarmuka pengguna. App shell harus:
- muat cepat
- di-cache
- menampilkan konten secara dinamis
App shell adalah rahasia untuk mendapatkan performa yang dapat diandalkan. Bayangkan shell aplikasi seperti kumpulan kode yang akan dipublikasikan ke app store jika Anda membangun aplikasi native. Ini adalah beban yang diperlukan untuk memulai, tetapi mungkin bukan keseluruhan cerita. Hal ini membuat UI Anda tetap lokal dan mengambil konten secara dinamis melalui API.
Latar belakang
Artikel Progressive Web App milik Alex Russell menjelaskan bagaimana aplikasi web dapat secara progresif berubah melalui penggunaan dan izin pengguna untuk memberikan pengalaman yang lebih mirip aplikasi native, lengkap dengan dukungan offline, notifikasi push, dan kemampuan untuk ditambahkan ke layar utama. Hal ini sangat bergantung pada manfaat fungsi dan performa pekerja layanan dan kemampuan penyimpanan cache-nya. Hal ini memungkinkan Anda berfokus pada kecepatan, sehingga aplikasi web Anda mendapatkan pemuatan instan dan update rutin yang sama seperti yang biasa Anda lihat di aplikasi native.
Untuk memanfaatkan kemampuan ini secara optimal, kami memerlukan cara baru dalam memandang situs: arsitektur shell aplikasi.
Mari pelajari cara membuat struktur aplikasi menggunakan arsitektur shell aplikasi tambahan pekerja layanan. Kita akan melihat proses rendering sisi klien dan server serta berbagi contoh end-to-end yang dapat Anda coba saat ini.
Untuk menekankan poinnya, contoh di bawah ini menunjukkan pemuatan pertama aplikasi yang menggunakan arsitektur ini. Perhatikan toast 'App is ready for offline use' di bagian bawah layar. Jika update shell tersedia nanti, kita dapat memberi tahu pengguna untuk memuat ulang ke versi baru.
Apa yang dimaksud dengan pekerja layanan lagi?
Pekerja layanan adalah skrip yang berjalan di latar belakang, terpisah dari halaman web Anda. Layanan ini merespons peristiwa, termasuk permintaan jaringan yang dibuat dari halaman yang dilayaninya, dan mengirimkan pemberitahuan dari server Anda. Pekerja layanan sengaja memiliki masa pakai singkat. Properti gabungan aktif ketika mendapatkan peristiwa dan hanya berjalan selama perlu memprosesnya.
Pekerja layanan juga memiliki kumpulan API terbatas jika dibandingkan dengan JavaScript dalam konteks penjelajahan biasa. Ini adalah standar untuk pekerja di web. Pekerja layanan tidak dapat mengakses DOM, tetapi dapat mengakses berbagai hal seperti Cache API, dan dapat membuat permintaan jaringan menggunakan Fetch API. tensorflow API dan postMessage() juga tersedia untuk digunakan untuk persistensi data dan pengiriman pesan antara pekerja layanan dan halaman yang dikontrolnya. Peristiwa push yang dikirim dari server Anda dapat memanggil Notification API untuk meningkatkan engagement pengguna.
Pekerja layanan dapat mencegat permintaan jaringan yang dibuat dari halaman (yang memicu peristiwa pengambilan pada pekerja layanan) dan menampilkan respons yang diambil dari jaringan, atau diambil dari cache lokal, atau bahkan dibuat secara terprogram. Sebenarnya, ini adalah proxy yang dapat diprogram dalam browser. Bagian yang tepat adalah, dari mana pun respons berasal, tampilan halaman web akan terlihat seolah-olah tidak ada keterlibatan pekerja layanan.
Untuk mempelajari lebih lanjut pekerja layanan secara mendalam, baca Pengantar Service Worker.
Manfaat performa
Pekerja layanan sangat berguna untuk caching offline dan juga menawarkan peningkatan performa yang signifikan dalam bentuk pemuatan instan untuk kunjungan berulang ke situs atau aplikasi web Anda. Anda dapat meng-cache shell aplikasi agar dapat berfungsi secara offline dan mengisi kontennya menggunakan JavaScript.
Pada kunjungan berulang, hal ini memungkinkan Anda menampilkan piksel yang bermakna di layar tanpa jaringan, sekalipun konten Anda pada akhirnya berasal dari jaringan tersebut. Anggap saja menampilkan toolbar dan kartu segera, lalu memuat konten lainnya secara progresif.
Untuk menguji arsitektur ini di perangkat sebenarnya, kami telah menjalankan contoh shell aplikasi di WebPageTest.org dan menampilkan hasilnya di bawah.
Pengujian 1: Pengujian pada Kabel dengan Nexus 5 menggunakan Chrome Dev
Tampilan pertama aplikasi harus mengambil semua resource dari jaringan dan tidak mencapai warna yang berarti hingga 1,2 detik masuk. Berkat penyimpanan cache pekerja layanan, kunjungan berulang kami mencapai hasil yang signifikan dan pemuatan penuh dalam waktu 0,5 detik.
Pengujian 2: Menguji pada 3G dengan Nexus 5 menggunakan Chrome Dev
Kami juga dapat menguji sampel dengan koneksi 3G yang sedikit lebih lambat. Kali ini dibutuhkan waktu 2,5 detik pada kunjungan pertama untuk cat pertama kami yang bermakna. Perlu waktu 7,1 detik untuk memuat halaman sepenuhnya. Dengan cache pekerja layanan, kunjungan berulang kami mencapai hasil yang optimal dan pemuatan penuh dalam waktu 0,8 detik.
Penayangan lain menceritakan hal serupa. Bandingkan 3 detik yang diperlukan untuk mencapai penggambaran pertama yang bermakna di shell aplikasi:
ke 0,9 detik yang diperlukan saat halaman yang sama dimuat dari cache pekerja layanan. Lebih dari 2 detik waktu disimpan untuk pengguna akhir kami.
Peningkatan performa yang serupa dan andal dimungkinkan untuk aplikasi Anda sendiri menggunakan arsitektur shell aplikasi.
Apakah pekerja layanan mengharuskan kita untuk memikirkan kembali cara kita menyusun aplikasi?
Service worker menyiratkan beberapa perubahan kecil dalam arsitektur aplikasi. Daripada memampatkan semua aplikasi Anda ke dalam string HTML, akan lebih baik jika Anda melakukan berbagai hal dengan gaya AJAX. Di sinilah Anda memiliki shell (yang selalu di-cache dan selalu dapat melakukan booting tanpa jaringan) dan konten yang dimuat ulang secara rutin dan dikelola secara terpisah.
Implikasi dari pemisahan ini cukup besar. Pada kunjungan pertama, Anda bisa merender konten di server dan menginstal pekerja layanan di klien. Pada kunjungan berikutnya, Anda hanya perlu meminta data.
Bagaimana dengan {i>progressive enhancement<i}?
Meskipun saat ini pekerja layanan tidak didukung oleh semua browser, arsitektur shell konten aplikasi menggunakan progressive enhancement untuk memastikan semua orang dapat mengakses konten. Misalnya, ambil contoh proyek kami.
Di bawah ini Anda dapat melihat versi lengkap yang dirender di Chrome, Firefox Nightly, dan Safari. Di sebelah kiri, Anda dapat melihat versi Safari tempat konten dirender di server tanpa pekerja layanan. Di sebelah kanan kita melihat versi Chrome dan Firefox Nightly yang didukung oleh pekerja layanan.
Kapan waktu yang tepat untuk menggunakan arsitektur ini?
Arsitektur shell aplikasi paling cocok untuk aplikasi dan situs yang dinamis. Jika situs Anda kecil dan statis, Anda mungkin tidak memerlukan shell aplikasi dan cukup meng-cache seluruh situs dalam langkah oninstall
pekerja layanan. Gunakan pendekatan yang paling masuk akal untuk proyek Anda. Sejumlah framework JavaScript sudah mendorong pemisahan logika aplikasi dari konten, sehingga membuat pola ini lebih mudah diterapkan.
Apakah ada aplikasi produksi yang menggunakan pola ini?
Arsitektur shell aplikasi dapat dilakukan hanya dengan sedikit perubahan pada UI aplikasi Anda secara keseluruhan dan telah berfungsi dengan baik untuk situs berskala besar seperti Progressive Web App I/O 2015 dan Kotak Masuk Google.
Shell aplikasi offline merupakan keunggulan utama performa dan juga ditunjukkan dengan baik dalam aplikasi Wikipedia offline Jake Archibald dan aplikasi web progresif Flipkart Lite.
Menjelaskan arsitektur
Selama pengalaman pemuatan pertama, tujuan Anda adalah menghadirkan konten yang bermakna ke layar pengguna secepat mungkin.
Pemuatan pertama dan pemuatan halaman lainnya
Secara umum, arsitektur shell aplikasi akan:
Memprioritaskan pemuatan awal, tetapi membiarkan pekerja layanan meng-cache shell aplikasi sehingga kunjungan berulang tidak memerlukan shell untuk diambil ulang dari jaringan.
Pemuatan lambat atau pemuatan latar belakang yang lain. Salah satu opsi yang bagus adalah menggunakan cache baca-tayang untuk konten dinamis.
Menggunakan alat pekerja layanan, seperti sw-precache, misalnya untuk meng-cache dan mengupdate pekerja layanan yang mengelola konten statis dengan andal. (Selengkapnya tentang sw-precache nanti.)
Untuk mencapai hal ini:
Server akan mengirim konten HTML yang dapat dirender oleh klien dan menggunakan header habis masa berlaku cache HTTP di masa mendatang untuk memperhitungkan browser tanpa dukungan pekerja layanan. Fungsi ini akan menyediakan nama file menggunakan hash untuk mengaktifkan 'pembuatan versi' dan update yang mudah untuk nanti dalam siklus proses aplikasi.
Halaman akan menyertakan gaya CSS inline di tag
<style>
dalam dokumen<head>
untuk memberikan penggambaran pertama yang cepat pada shell aplikasi. Setiap halaman akan memuat JavaScript yang diperlukan untuk tampilan saat ini secara asinkron. Karena CSS tidak dapat dimuat secara asinkron, kita dapat meminta gaya menggunakan JavaScript karena CSS adalah asinkron, bukan berbasis parser dan sinkron. Kita juga dapat memanfaatkanrequestAnimationFrame()
untuk menghindari kasus saat cache ditemukan dengan cepat dan akhirnya gaya tidak sengaja menjadi bagian dari jalur rendering penting.requestAnimationFrame()
memaksa frame pertama untuk dilukis sebelum gaya dimuat. Opsi lainnya adalah menggunakan project seperti loadCSS Filament Group untuk meminta CSS secara asinkron menggunakan JavaScript.Service worker akan menyimpan entri shell aplikasi yang di-cache sehingga pada kunjungan berulang, shell dapat dimuat sepenuhnya dari cache pekerja layanan, kecuali jika update tersedia di jaringan.
Implementasi praktis
Kami telah menulis contoh yang berfungsi sepenuhnya menggunakan arsitektur shell aplikasi, vanilla ES2015 JavaScript untuk klien, dan Express.js untuk server. Tentu saja tidak ada yang menghentikan Anda menggunakan stack Anda sendiri untuk bagian klien atau server (misalnya PHP, Ruby, Python).
Siklus proses pekerja layanan
Untuk project shell aplikasi, kita menggunakan sw-precache yang menawarkan siklus proses pekerja layanan berikut:
Acara | Action |
---|---|
Menginstal | Cache shell aplikasi dan resource aplikasi web satu halaman lainnya. |
Aktifkan | Hapus cache lama. |
Ambil | Menayangkan aplikasi web satu halaman untuk URL dan menggunakan cache untuk aset dan parsial yang telah ditetapkan. Gunakan jaringan untuk permintaan lainnya. |
Bit server
Dalam arsitektur ini, komponen sisi server (dalam kasus ini, ditulis dalam Express) harus dapat menangani konten dan presentasi secara terpisah. Konten dapat ditambahkan ke tata letak HTML yang menghasilkan render statis halaman, atau dapat ditayangkan secara terpisah dan dimuat secara dinamis.
Perlu dipahami, penyiapan sisi server Anda mungkin sangat berbeda dengan yang kami gunakan untuk aplikasi demo kami. Pola aplikasi web ini dapat dilakukan oleh sebagian besar penyiapan server, meskipun membutuhkan arsitektur ulang. Kami mendapati bahwa model berikut berfungsi cukup baik:
Endpoint ditentukan untuk tiga bagian aplikasi: URL (indeks/karakter pengganti) yang dilihat pengguna, shell aplikasi (pekerja layanan), dan parsial HTML Anda.
Setiap endpoint memiliki pengontrol yang menarik tata letak handlebar, yang kemudian dapat menarik bagian setang dan tampilan. Sederhananya, parsial adalah tampilan yang merupakan potongan-potongan HTML yang disalin ke laman akhir. Catatan: Framework JavaScript yang melakukan sinkronisasi data yang lebih canggih sering kali jauh lebih mudah untuk ditransfer ke arsitektur Shell Aplikasi. Model tersebut cenderung menggunakan data binding dan sinkronisasi, bukan parsial.
Pengguna awalnya akan melihat halaman statis yang berisi konten. Halaman ini mendaftarkan pekerja layanan, jika didukung, yang meng-cache shell aplikasi dan semua yang bergantung padanya (CSS, JS, dll.).
Shell aplikasi kemudian akan bertindak sebagai aplikasi web satu halaman, menggunakan javascript ke XHR dalam konten untuk URL tertentu. Panggilan XHR dibuat ke endpoint /partials* yang mengembalikan potongan kecil HTML, CSS, dan JS yang diperlukan untuk menampilkan konten tersebut. Catatan: Ada banyak cara untuk menangani hal ini dan XHR hanyalah salah satunya. Beberapa aplikasi akan menyisipkan datanya (mungkin menggunakan JSON) untuk render awal, sehingga tidak "statis" dalam artian HTML yang disatukan.
Browser tanpa dukungan pekerja layanan harus selalu mendapatkan pengalaman penggantian. Dalam demo, kita kembali ke rendering sisi server statis dasar, tetapi ini hanyalah salah satu dari banyak opsi. Aspek pekerja layanan memberi Anda peluang baru untuk meningkatkan performa aplikasi Gaya Aplikasi Web Satu Halaman menggunakan shell aplikasi yang di-cache.
Pembuatan versi file
Satu pertanyaan yang muncul adalah bagaimana menangani pembuatan versi dan pembaruan file. Ini khusus aplikasi dan opsinya adalah:
Network terlebih dahulu dan gunakan versi yang di-cache.
Jaringan saja dan gagal jika offline.
Cache versi lama dan update nanti.
Untuk shell aplikasi itu sendiri, pendekatan cache-first harus diambil untuk penyiapan pekerja layanan. Jika Anda tidak meng-cache shell aplikasi, Anda belum mengadopsi arsitektur dengan benar.
Alat
Kami mengelola sejumlah library helper pekerja layanan yang berbeda, sehingga mempermudah penyiapan untuk proses pra-cache shell aplikasi Anda atau penanganan pola caching umum.
Menggunakan sw-precache untuk shell aplikasi Anda
Penggunaan sw-precache untuk meng-cache shell aplikasi akan dapat mengatasi permasalahan seputar revisi file, pertanyaan instal/aktifkan, dan skenario pengambilan untuk app shell. Terapkan sw-precache ke dalam proses build aplikasi Anda dan gunakan karakter pengganti yang dapat dikonfigurasi untuk mengambil resource statis. Daripada membuat skrip pekerja layanan secara manual, biarkan sw-precache membuat skrip yang mengelola cache Anda secara aman dan efisien, menggunakan pengendali pengambilan yang memprioritaskan cache.
Kunjungan awal ke aplikasi Anda memicu precache rangkaian lengkap resource yang diperlukan. Ini mirip dengan pengalaman menginstal aplikasi native dari app store. Saat pengguna kembali ke aplikasi Anda, hanya resource terbaru yang akan didownload. Dalam demo ini, kami memberi tahu pengguna saat shell baru tersedia dengan pesan, "Update aplikasi. Muat ulang untuk versi baru." Pola ini merupakan cara yang mudah untuk memberi tahu pengguna bahwa mereka dapat memuat ulang ke versi terbaru.
Menggunakan sw-toolbox untuk penyimpanan cache runtime
Gunakan sw-toolbox untuk penyimpanan cache runtime dengan berbagai strategi, bergantung pada resource:
cacheFirst untuk gambar, beserta cache bernama khusus yang memiliki kebijakan habis masa berlaku khusus untuk N maxEntries.
networkFirst atau tercepat untuk permintaan API, bergantung pada keaktualan konten yang diinginkan. Mempercepat mungkin tidak masalah, tetapi jika ada feed API tertentu yang sering diperbarui, gunakan networkFirst.
Kesimpulan
Arsitektur shell aplikasi memiliki beberapa manfaat, tetapi hanya relevan untuk beberapa kelas aplikasi. Model ini masih muda dan sebaiknya mengevaluasi upaya dan manfaat performa secara keseluruhan dari arsitektur ini.
Dalam eksperimen, kami memanfaatkan berbagi template antara klien dan server untuk meminimalkan pekerjaan membangun dua lapisan aplikasi. Hal ini memastikan bahwa {i>progressive enhancement <i}masih menjadi fitur inti.
Jika Anda sudah mempertimbangkan untuk menggunakan pekerja layanan di aplikasi, lihat arsitekturnya dan evaluasi apakah ini cocok untuk project Anda sendiri.
Terima kasih kepada peninjau kami: Jeff Posnick, Paul Lewis, Alex Russell, Seth Thompson, Rob Dodson, Taylor Savage, dan Joe Medley.