Pada bulan April tahun ini, kami menerbitkan terjemahan dari
materi pertama dari seri yang ditujukan untuk pendekatan yang bertanggung jawab terhadap pengembangan JavaScript. Di sana, penulis merefleksikan teknologi web modern dan penggunaan rasionalnya. Sekarang kami menawarkan Anda terjemahan dari artikel kedua dari seri ini. Ini dikhususkan untuk beberapa rincian teknis mengenai desain proyek web.

Punya ide
Anda dan tim Anda dengan antusias mempromosikan gagasan perombakan total situs web perusahaan yang menua. Permintaan Anda mencapai kepemimpinan, bahkan muncul di hadapan mereka yang berada di puncak. Anda diberi lampu hijau. Tim Anda dengan antusias mulai bekerja, menarik desainer, copywriter, dan spesialis lain ke dalamnya. Segera Anda meluncurkan kode baru.
Pekerjaannya dimulai dengan polos.
npm install
ada di sini, perintah
npm install
ada di sana. Segera setelah Anda melihat-lihat, ketergantungan produksi sudah ditetapkan seolah-olah pengembangan proyek adalah minuman keras, dan Anda adalah orang yang tidak peduli sama sekali tentang apa yang akan terjadi besok pagi.
Lalu kamu mulai.
Tetapi, tidak seperti konsekuensi dari pesta minum paling gila, hal buruk tidak dimulai keesokan paginya. Sayangnya - bukan keesokan paginya. Perhitungan dilakukan dalam beberapa bulan. Dia mengambil bentuk mual dan sakit kepala ringan yang tidak menyenangkan bagi pemilik perusahaan dan manajer menengah yang bertanya-tanya mengapa, setelah peluncuran situs baru, konversi dan pendapatan turun. Kemudian bencana itu mendapatkan momentum. Ini terjadi ketika direktur teknis kembali dari akhir pekan, yang ia habiskan di suatu tempat di luar kota. Dia bertanya-tanya mengapa situs web perusahaan memuat dengan sangat lambat (jika ada) di teleponnya.
Dulu baik untuk semua orang. Sekarang zaman kegelapan lainnya telah datang. Memenuhi hangover pertama Anda setelah mengonsumsi JavaScript dalam dosis besar.
Ini bukan salahmu.
Sementara Anda mencoba untuk mengatasi mabuk berat, kata-kata seperti "Saya sudah bilang begitu" akan terdengar seperti teguran yang pantas untuk Anda. Dan jika Anda bisa bertarung pada saat itu, mereka bisa berfungsi sebagai kesempatan untuk berkelahi.
Ketika datang ke konsekuensi dari penggunaan sembrono JavaScript, Anda dapat menyalahkan segalanya dan semua orang. Tapi mencari yang bersalah itu buang-buang waktu. Perangkat web modern itu sendiri menuntut perusahaan untuk menyelesaikan masalah lebih cepat daripada pesaing mereka. Tekanan seperti itu berarti bahwa kita, berusaha untuk meningkatkan produktivitas kita sebanyak mungkin, kemungkinan akan meraih apa pun. Ini berarti bahwa kami, dengan tingkat probabilitas yang tinggi (meskipun ini tidak dapat disebut tak terhindarkan), akan membuat aplikasi yang akan ada banyak kelebihan, dan, kemungkinan besar, kami akan menggunakan pola yang merusak kinerja dan ketersediaan aplikasi.
Pengembangan web bukanlah tugas yang mudah. Ini pekerjaan yang panjang. Ini jarang dilakukan dengan baik pada percobaan pertama. Namun, hal terbaik tentang pekerjaan ini adalah bahwa kita tidak harus melakukan semuanya dengan sempurna di awal. Kami dapat melakukan perbaikan pada proyek setelah diluncurkan, dan, pada kenyataannya, materi ini didedikasikan untuk ini, yang kedua dalam serangkaian artikel tentang pendekatan yang bertanggung jawab terhadap pengembangan JS. Kesempurnaan adalah tujuan yang sangat jauh. Sementara itu, mari kita berurusan dengan hangover JavaScript dengan meningkatkan, jadi,
scriptingdi situs dalam waktu dekat.
Kami menangani masalah umum
Ini mungkin tampak seperti pendekatan mekanis untuk menyelesaikan masalah, tetapi pertama-tama pelajari daftar masalah dan cara khas untuk mengatasinya. Dalam tim pengembangan besar, hal-hal ini sering dilupakan. Ini terutama berlaku untuk tim-tim yang bekerja dengan banyak repositori atau tidak menggunakan templat yang dioptimalkan untuk proyek mereka.
β Terapkan algoritma pengocokan pohon
Pertama, periksa apakah alat Anda dikonfigurasi untuk mengimplementasikan algoritma
pengocokan pohon . Jika Anda belum menemukan konsep ini sebelumnya, lihatlah materi
saya yang ditulis tahun lalu. Jika kita menjelaskan operasi algoritma ini secara singkat, maka kita dapat mengatakan bahwa karena penggunaannya dalam rakitan produksi aplikasi tidak termasuk paket-paket yang, meskipun diimpor ke proyek, tidak digunakan di dalamnya.
Implementasi algoritma pengocok pohon adalah fitur standar dari bundler modern seperti
webpack ,
Rollup atau
Parcel .
Grunt atau
tegukan adalah manajer tugas. Mereka tidak melakukan ini. Manajer tugas, tidak seperti bundler, tidak membuat
grafik ketergantungan . Manajer tugas terlibat, menggunakan plug-in yang diperlukan, melakukan manipulasi terpisah pada file yang ditransfer ke sana. Fungsionalitas pengelola tugas dapat diperluas menggunakan plugin, memberi mereka kemampuan untuk memproses JavaScript menggunakan bundler. Jika memperluas kemampuan manajer tugas ke arah ini tampaknya menjadi masalah, maka Anda mungkin perlu memeriksa basis kode secara manual dan menghapus kode yang tidak digunakan dari itu.
Agar algoritma pengocokan pohon dapat bekerja secara efisien, kondisi berikut ini harus dipenuhi:
- Kode aplikasi dan paket yang diinstal harus disajikan sebagai modul ES6 . Menggunakan algoritma pengocokan pohon untuk modul CommonJS hampir tidak mungkin.
- Bundler Anda tidak boleh mengubah modul ES6 menjadi modul dengan beberapa format lain selama pembangunan proyek. Jika ini terjadi di toolchain yang menggunakan Babel, maka @ Babel / present-env harus memiliki modul: pengaturan salah . Ini akan menyebabkan kode ES6 tidak dikonversi ke kode yang menggunakan CommonJS.
Jika tiba-tiba, ketika membangun proyek Anda, algoritma pengocokan pohon tidak diterapkan, dimasukkannya mekanisme ini dapat memperbaiki situasi. Tentu saja, efektifitas algoritma ini bervariasi dari proyek ke proyek. Selain itu, kemungkinan penggunaannya tergantung pada apakah modul yang diimpor memiliki
efek samping . Ini dapat memengaruhi kemampuan bundler untuk menyingkirkan masuknya modul impor yang tidak perlu dalam perakitan.
β Bagilah kode menjadi beberapa bagian
Sangat mungkin bahwa Anda sudah menggunakan beberapa bentuk
pemisahan kode . Namun, Anda harus memeriksa bagaimana ini dilakukan. Terlepas dari bagaimana Anda memisahkan kode, saya ingin menawarkan kepada Anda untuk bertanya pada diri sendiri dua pertanyaan yang sangat berharga berikut:
- Apakah Anda menghapus kode duplikat dari titik input ?
- Apakah Anda malas memuat semua yang dapat dimuat dengan cara ini dengan impor dinamis ?
Masalah-masalah ini penting karena mengurangi jumlah kode yang berlebihan adalah elemen kinerja yang penting. Malas memuat kode juga meningkatkan kinerja dengan mengurangi jumlah kode JavaScript yang merupakan bagian dari halaman dan memuat ketika itu dimuat. Jika kita berbicara tentang analisis proyek untuk keberadaan kode yang berlebihan di dalamnya, maka untuk ini Anda dapat menggunakan beberapa jenis alat seperti Bundle Buddy. Jika proyek Anda memiliki masalah dengan ini, alat ini akan memberi tahu Anda tentang itu.
Alat Budak Bundel dapat memeriksa informasi kompilasi webpack dan mencari tahu berapa banyak kode yang sama digunakan dalam bundel AndaJika kita berbicara tentang pemuatan materi yang malas, maka mencari tahu di mana mencari peluang untuk menerapkan pengoptimalan ini dapat menjadi beberapa kesulitan. Ketika saya meneliti proyek yang ada untuk kemungkinan menggunakan lazy loading, saya mencari di basis kode untuk tempat-tempat yang melibatkan interaksi pengguna dengan kode. Ini bisa, misalnya, pengendali acara mouse atau keyboard, serta hal-hal serupa lainnya. Kode apa pun yang memerlukan beberapa tindakan pengguna untuk dijalankan adalah kandidat yang baik untuk menerapkan perintah
import()
dinamis
import()
ke kode tersebut.
Tentu saja, memuat skrip sesuai permintaan membawa risiko keterlambatan nyata dalam memindahkan sistem ke mode interaktif. Memang, sebelum program dapat berinteraksi dengan pengguna secara interaktif, Anda perlu mengunduh skrip yang sesuai. Jika jumlah data yang ditransfer tidak mengganggu Anda, pertimbangkan untuk menggunakan petunjuk
rel = prefetch sumber daya untuk memuat skrip prioritas rendah tersebut. Sumber daya semacam itu tidak akan bersaing untuk bandwidth dengan sumber daya kritis. Jika browser pengguna
mendukung rel=prefetch
, menggunakan tooltip ini hanya akan bermanfaat. Jika tidak, maka tidak ada hal buruk yang akan terjadi, karena browser mengabaikan markup yang tidak mereka mengerti.
βGunakan opsi eksternal webpack untuk menandai sumber daya yang berada di server asing
Idealnya, Anda harus meng-host sebanyak mungkin dependensi situs Anda di server Anda sendiri. Jika karena alasan tertentu Anda, tanpa opsi, harus mengunduh dependensi dari server orang lain - letakkan di blok
eksternal di pengaturan webpack. Jika ini tidak dilakukan, ini berarti bahwa pengunjung situs Anda akan mengunduh kode yang Anda host dan kode yang sama dari server orang lain.
Lihatlah situasi hipotetis di mana sesuatu seperti ini dapat membahayakan sumber daya Anda. Misalkan situs Anda mengunduh perpustakaan Lodash dari sumber CDN publik. Anda juga menginstal Lodash di proyek untuk tujuan pengembangan lokal. Namun, jika Anda tidak menentukan dalam pengaturan webpack bahwa Lodash adalah ketergantungan eksternal, maka kode produksi Anda akan memuat pustaka dari CDN, tetapi pada saat yang sama akan dimasukkan dalam bundel yang di-host di server Anda.
Jika Anda terbiasa dengan bundler, maka semua ini mungkin bagi Anda kebenaran biasa. Tetapi saya melihat bagaimana hal-hal ini tidak memperhatikan. Karena itu, jangan meluangkan waktu untuk memeriksa proyek Anda untuk masalah di atas.
Jika Anda tidak menganggap perlu untuk meng-host dependensi Anda yang dibuat oleh pengembang pihak ketiga sendiri, maka pertimbangkan untuk menggunakan
dns-prefetch ,
preconnect , atau mungkin bahkan
preload petunjuk dengan mereka. Ini dapat mengurangi skor
TTI (Time To Interactive, waktu situs ke interaktivitas pertama). Dan jika kemampuan JavaScript diperlukan untuk menampilkan konten situs, maka
Indeks Kecepatan situs
juga diperlukan.
Perpustakaan alternatif yang lebih kecil dan pengurangan overhead pada sistem pengguna
Apa yang disebut "
Userland JavaScript " (perpustakaan JS yang dikembangkan pengguna) tampaknya seperti toko permen yang cabul. Semua keindahan dan keragaman open-source ini menginspirasi kami, pengembang, dengan kagum. Kerangka kerja dan pustaka memungkinkan kita untuk memperluas aplikasi kita, dengan cepat melengkapi mereka dengan fitur yang membantu menyelesaikan berbagai masalah. Jika kita harus mengimplementasikan fungsi yang sama sendiri, itu akan membutuhkan banyak waktu dan energi.
Meskipun saya pribadi menganjurkan minimalisasi agresif penggunaan kerangka kerja klien dan perpustakaan di proyek-proyek saya, saya tidak bisa tidak mengakui nilai besar dan kegunaannya. Namun, terlepas dari ini, ketika harus menginstal dependensi baru dalam proyek, kita harus memperlakukan mereka masing-masing dengan kecurigaan yang adil. Jika kita telah membuat dan meluncurkan sesuatu, operasi yang tergantung pada banyak dependensi yang diinstal, maka ini berarti bahwa kita tahan dengan beban tambahan pada sistem yang semua ini buat. Kemungkinan hanya pengembang paket yang dapat mengatasi masalah ini dengan mengoptimalkan pengembangannya. Benarkah begitu?
Mungkin memang begitu, tapi mungkin juga tidak. Itu tergantung pada dependensi yang digunakan. Misalnya, React adalah perpustakaan yang sangat populer. Tetapi
Preact adalah alternatif yang
sangat kecil untuk React, yang memberikan pengembang API yang hampir sama dan tetap kompatibel dengan banyak add-on React.
Luxon dan
date-fns adalah alternatif untuk
moment.js , jauh lebih ringkas dari perpustakaan ini, yang
tidak begitu kecil .
Di perpustakaan seperti
Lodash, Anda dapat menemukan banyak metode yang berguna. Tetapi beberapa dari mereka mudah diganti dengan metode ES6 standar. Misalnya, metode Lodash
compact dapat diganti dengan metode array
filter standar.
Banyak metode Lodash lainnya juga dapat diganti dengan aman dengan metode standar. Keuntungan dari penggantian ini adalah bahwa kami mendapatkan fitur yang sama seperti menggunakan perpustakaan, tetapi menyingkirkan ketergantungan yang agak besar.
Apa pun yang Anda gunakan, ide umumnya tetap sama: tanyakan apakah pilihan Anda memiliki alternatif yang lebih ringkas. Cari tahu apakah Anda dapat memecahkan masalah yang sama dengan alat bahasa standar. Mungkin Anda akan terkejut dengan betapa sedikit Anda harus melakukan upaya untuk secara serius mengurangi ukuran aplikasi dan jumlah beban yang tidak perlu yang diberikannya pada sistem pengguna.
Gunakan teknologi pemuatan diferensial skrip
Kemungkinannya adalah Babel ada di rantai alat Anda. Alat ini digunakan untuk mengubah kode sumber yang sesuai dengan ES6 menjadi kode yang dapat dijalankan oleh browser lawas. Apakah ini berarti bahwa kita ditakdirkan untuk memberikan bundel besar bahkan untuk browser yang tidak membutuhkannya, sampai semua browser lama hilang begitu saja?
Tentu tidak ! Pemuatan sumber daya diferensial membantu menghindari masalah ini dengan membuat dua majelis berbeda berdasarkan kode ES6:
- Perakitan pertama mencakup semua konversi kode dan polyfill yang diperlukan agar situs Anda berfungsi di browser lawas. Mungkin sekarang Anda memberi pelanggan perakitan khusus ini.
- Majelis kedua berisi minimal kode dan konversi polyfill, atau tidak sama sekali. Ini dirancang untuk browser modern. Ini adalah majelis yang mungkin tidak Anda miliki. Setidaknya belum.
Untuk menggunakan teknologi pemuatan majelis yang berbeda, Anda harus bekerja sedikit. Saya tidak akan membahas detailnya di sini - Saya akan memberikan
tautan yang lebih baik ke materi saya, yang membahas salah satu cara untuk menerapkan teknologi ini. Inti dari semua ini adalah Anda dapat memodifikasi konfigurasi build Anda sehingga selama pembangunan proyek versi tambahan dari bundel JS situs Anda dibuat. Bundel tambahan ini akan lebih kecil dari bundel utama. Ini akan ditujukan hanya untuk browser modern. Bagian terbaiknya adalah bahwa pendekatan ini memungkinkan Anda untuk mengoptimalkan ukuran bundel dan pada saat yang sama tidak mengorbankan apa pun dari kemampuan proyek. Tergantung pada kode aplikasi, penghematan ukuran bundel bisa sangat signifikan.
Analisis bundel untuk browser lawas (kiri) dan bundel untuk browser baru (kanan). Studi bundel dilakukan dengan menggunakan webpack-bundle-analyzer. Ini adalah versi ukuran penuh dari gambar ini.Cara termudah untuk memberikan bundel berbeda ke browser berbeda menggunakan trik berikut. Ini berfungsi dengan baik di browser modern:
<!-- : --> <script type="module" src="/js/app.mjs"></script> <!-- : --> <script defer nomodule src="/js/app.js"></script>
Sayangnya, pendekatan ini memiliki kelemahan. Browser yang ketinggalan jaman seperti IE11, dan bahkan yang relatif modern seperti Edge versi 15-18, akan memuat kedua bundel. Jika Anda siap untuk menggunakannya - maka gunakan teknik ini dan jangan khawatir tentang apa pun.
Di sisi lain, Anda perlu menemukan sesuatu jika Anda khawatir tentang
dampak pada kinerja aplikasi Anda dari fakta bahwa browser lama harus mengunduh kedua bundel. Berikut adalah salah satu solusi potensial untuk masalah ini yang menggunakan injeksi skrip (bukan tag
<script>
kami gunakan di atas). Ini menghindari pemuatan ganda bundel oleh browser yang tepat. Inilah yang sedang kita bicarakan:
var scriptEl = document.createElement("script"); if ("noModule" in scriptEl) {
Skrip ini mengasumsikan bahwa jika browser mendukung atribut
nomodule dalam elemen
script
, maka ia memahami konstruk
type="module"
. Ini memastikan bahwa browser lawas hanya akan menerima skrip yang dirancang untuk mereka, dan yang modern akan menerima skrip yang dirancang untuk mereka. Namun, perlu diingat bahwa skrip tertanam secara dinamis dimuat secara asinkron secara default. Oleh karena itu, jika urutan memuat dependensi penting bagi Anda, setel atribut
async ke
false
.
Sampaikan lebih sedikit
Saya tidak akan menyerang Babel di sini. Alat ini diperlukan dalam pengembangan web modern, tetapi merupakan entitas yang sangat bandel. Babel menambahkan banyak hal ke kode yang dihasilkannya, yang mungkin tidak diketahui pengembang. Karena itu, Anda tidak akan menyesal jika Anda melihat isi perut Babel dan mencari tahu apa yang sedang dilakukannya. Secara khusus, pengetahuan tentang mekanisme internal Babel membuat jelas bahwa perubahan kecil pada bagaimana seseorang menulis kode dapat memiliki efek positif pada apa yang dihasilkan Babel.
Sampaikan lebih sedikitYaitu - itulah yang sedang kita bicarakan. Misalnya,
opsi default adalah fitur yang sangat berguna dari ES6 yang mungkin sudah Anda gunakan:
function logger(message, level = "log") { console[level](message); }
Di sini perlu diperhatikan parameter
level
, yang nilai defaultnya adalah
log
string. Ini berarti bahwa jika kita ingin memanggil
console.log
menggunakan fungsi wrapper
logger
, maka kita tidak perlu melewati
level
ke fungsi ini. Nyaman bukan? Semua ini baik - kecuali untuk kode apa yang didapat Babel saat mengubah fungsi ini:
function logger(message) { var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "log"; console[level](message); }
Ini adalah contoh bagaimana, terlepas dari kenyataan bahwa kita dipimpin oleh niat baik, kenyamanan yang diberikan Babel dapat menyebabkan konsekuensi negatif. Apa yang hanya beberapa karakter dalam kode sumber berubah menjadi konstruksi yang jauh lebih lama dalam versi produksi program. - , ,
arguments
.
, ,
? , Babel :
, Babel
@babel/preset-env ,
. , , , , , ! β «» (
true
loose ). β , , , , , . «»
, Babel , .
, «» , , Babel :
, β JavaScript, , .
spread ,
,
.
β :
- β @babel/runtime @babel/plugin-transform-runtime , , Babel .
- , . @babel/polyfill . , babel /preset-env useBuiltins
usage
.
, , , , , . ,
JSX , , , . , , . , , . , Babel β . , Babel. , .
: β
, . , JavaScript-, , . , , . - .
. , , , , , , , .
, , , , , , , . - β . , , , . . , , , , . , , , .
Pembaca yang budiman! JS-?
