
Pemecahan kode. Pemecahan kode ada di mana-mana. Namun mengapa? Hanya karena ada terlalu banyak javascript saat ini, dan tidak semua digunakan pada saat yang sama.
JS adalah hal yang sangat berat . Bukan untuk iPhone Xs atau laptop i9 baru Anda, tetapi untuk jutaan (mungkin miliaran) pemilik perangkat yang lebih lambat . Atau, setidaknya, untuk jam tangan Anda.
Jadi - JS itu buruk, tetapi apa yang akan terjadi jika kita menonaktifkannya - masalahnya akan hilang ... untuk beberapa situs, dan hilang "dengan situs" untuk yang berbasiskan Bereaksi. Tapi bagaimanapun - ada situs, yang bisa berfungsi tanpa JS ... dan ada sesuatu yang harus kita pelajari dari mereka ...
Pemecahan kode
Hari ini kita memiliki dua cara untuk maju, dua cara untuk membuatnya lebih baik, atau untuk tidak memperburuknya:
1. Tulis lebih sedikit kode
Itu hal terbaik yang bisa Anda lakukan. Sementara React Hooks
memungkinkan Anda mengirimkan kode sedikit lebih sedikit, dan solusi seperti Svelte
memungkinkan Anda menghasilkan kode lebih sedikit dari biasanya , itu tidak mudah dilakukan.
Ini bukan hanya tentang kode, tetapi juga tentang fungsionalitas - untuk menjaga kode "kompak" Anda harus tetap "kompak". Tidak ada cara untuk menjaga bundel aplikasi tetap kecil jika ia melakukan banyak hal (dan dikirimkan dalam 20 bahasa).
Ada cara untuk menulis kode pendek dan suara , dan ada cara untuk menulis implementasi yang berlawanan - perusahaan berdarah . Dan, Anda tahu, keduanya sah.

Tetapi masalah utama - kode itu sendiri. Aplikasi reaksi sederhana dapat dengan mudah memotong 250kb "direkomendasikan". Dan Anda mungkin menghabiskan satu bulan untuk mengoptimalkannya dan membuatnya lebih kecil. Optimalisasi "Kecil" didokumentasikan dengan baik dan cukup bermanfaat - dapatkan bundle-analyzer
dengan size-limit
dan kembalilah ke bentuk semula.
Ada banyak pustaka, yang berjuang untuk setiap byte, mencoba membuat Anda dalam batas Anda - preact dan storeon , untuk menyebutkan beberapa.
Tetapi aplikasi kami sedikit melebihi 200kb. Lebih dekat ke 100Mb . Menghapus kilobyte tidak masuk akal. Bahkan menghapus megabita tidak masuk akal.
Setelah beberapa saat, aplikasi Anda tetap kecil. Ini akan tumbuh lebih besar seiring waktu.
2. Kirimkan kode lebih sedikit
Atau, code split
. Dengan kata lain - menyerah . Ambil 100mb bundel Anda, dan buat dua puluh 5mb bundel darinya. Jujur - itu satu-satunya cara yang mungkin untuk menangani aplikasi Anda jika itu besar - buat paket aplikasi yang lebih kecil darinya.
Tetapi ada satu hal yang harus Anda ketahui saat ini: opsi apa pun yang Anda pilih, itu adalah detail implementasi, sementara kami sedang mencari sesuatu yang lebih dapat diandalkan.
Kebenaran tentang Pemecahan Kode
Kebenaran tentang pemisahan kode adalah sifatnya adalah SEPARASI WAKTU . Anda tidak hanya membelah kode Anda, Anda membaginya dengan cara di mana Anda akan menggunakan sesedikit mungkin dalam satu titik waktu.
Hanya saja, jangan mengirim kode yang tidak Anda butuhkan saat ini. Singkirkan itu.

Mudah dikatakan, sulit dilakukan. Saya memiliki beberapa aplikasi berat, tetapi tidak cukup terpecah, di mana setiap halaman memuat 50% dari segalanya. Kadang-kadang code splitting
menjadi code separation
, maksud saya - Anda dapat memindahkan kode ke potongan yang berbeda, tetapi tetap saja, gunakan semuanya. Ingatlah kembali bahwa "Jangan kirimkan kode yang tidak Anda butuhkan saat ini" , - Saya membutuhkan 50% dari kode itu, dan itulah masalah sebenarnya.
Terkadang hanya menambahkan import
di sana-sini tidak cukup. Sampai ini bukan pemisahan waktu , tetapi hanya pemisahan ruang - tidak masalah sama sekali.
Ada 3 cara umum untuk membagi kode:
import
dinamis saja. Hampir tidak digunakan sendirian hari ini. Ini lebih tentang masalah dengan melacak negara .- Komponen
Lazy
, ketika Anda mungkin menunda rendering dan memuat Komponen Bereaksi. Mungkin 90% dari "reaksi pemecahan kode" hari ini. - Lazy
Library
, yang sebenarnya adalah .1
, tetapi Anda akan diberikan kode pustaka melalui React render props. Diimplementasikan dalam komponen reaksi-impor dan komponen yang dapat dimuat . Cukup bermanfaat, tetapi tidak terkenal.
Pemecahan Kode Level Komponen
Yang ini paling populer. Sebagai pemisahan kode per rute, atau pemisahan kode per komponen. Tidak mudah melakukannya dan mempertahankan hasil persepsi yang baik sebagai hasilnya. Ini kematian dari Flash of Loading Content
.
Teknik yang baik adalah:
- memuat
js chunk
dan data
untuk rute secara paralel. - gunakan
skeleton
untuk menampilkan sesuatu yang mirip dengan halaman sebelum memuat halaman (seperti Facebook). - potongan
prefetch
, Anda bahkan dapat menggunakan tebak-js untuk prediksi yang lebih baik. - gunakan beberapa penundaan, memuat indikator,
animations
dan Suspense
(di masa depan) untuk melunakkan transisi.
Dan, Anda tahu, itu semua tentang kinerja perseptual .

Gambar dari Peningkatan UX dengan Elemen Hantu
Kedengarannya tidak bagus
Anda tahu, saya bisa menyebut diri saya seorang ahli dalam pemecahan kode - tetapi saya memiliki kegagalan sendiri.
Kadang-kadang saya bisa gagal mengurangi ukuran bundel. Kadang-kadang saya bisa gagal meningkatkan kinerja yang dihasilkan, selama the _more_ code splitting you are introducing - the more you spatially split your page - the more time you need to _reassemble_ your page back
*. Ini disebut gelombang pemuatan .
- tanpa SSR atau pra-rendering. SSR yang tepat adalah pengubah game saat ini.

Minggu lalu saya mengalami dua kegagalan:
- Saya telah kehilangan satu perbandingan perpustakaan , selama perpustakaan saya lebih baik, tetapi JAUH lebih besar dari yang lain. Saya gagal "1. Tulis lebih sedikit kode" .
- mengoptimalkan situs kecil, dibuat di Bereaksi oleh istri saya. Itu menggunakan pemisahan komponen berbasis rute, tetapi
header
dan footer
disimpan dalam bundel utama untuk membuat transisi lebih "dapat diterima". Hanya beberapa hal, yang erat dipasangkan dengan sisi bundel yang meroket hingga 320 kb (sebelum gzip). Tidak ada yang penting, dan tidak ada yang bisa saya singkirkan. Kematian dengan seribu luka . Saya gagal mengirim kode lebih sedikit .
React-Dom adalah 20%, core-js adalah 10%, react-router, jsLingui, react-powerplug ... 20% dari kode sendiri ... Kita sudah selesai.

Solusinya
Saya mulai berpikir tentang bagaimana menyelesaikan masalah saya, dan mengapa solusi umum tidak berfungsi dengan baik untuk use case saya.
Apa yang saya lakukan? Saya telah membuat daftar semua lokasi penting, yang tanpanya aplikasi tidak akan berfungsi sama sekali, dan mencoba memahami mengapa saya memiliki sisanya.
Itu mengejutkan. Tapi masalah saya ada di CSS. Dalam transisi CSS vanilla.
Ini kodenya
Saya ingin memecah kode bagian ini secara keseluruhan, tetapi ini adalah sesuatu yang tidak dapat saya lakukan, karena dua alasan:
- informasi harus segera terlihat, sekali diperlukan, tanpa penundaan. Persyaratan bisnis.
- informasi "chrome" harus ada sebelumnya, untuk menangani transisi properti.
Masalah ini sebagian dapat diselesaikan menggunakan CSSTransitionGroup atau rekondisi . Tapi, Anda tahu, memperbaiki satu kode dengan menambahkan kode lain terdengar aneh, walaupun sebenarnya cukup. Maksud saya menambahkan lebih banyak kode dapat membantu menghilangkan lebih banyak kode. Tapi ... tapi ...
Harus ada cara yang lebih baik!
TL; DR - ada dua poin utama di sini:
DisplayData
harus dipasang , dan ada di DOM sebelumnya.FocusLock
juga harus ada sebelumnya, bukan untuk menyebabkan DisplayData
remount, tetapi otak itu tidak diperlukan di awal.
Jadi mari kita ubah model mental kita
Batman dan robin
Anggap kode kita adalah Batman dan Robin. Batman dapat menangani sebagian besar orang jahat, tetapi ketika dia tidak bisa, sahabat karibnya Robin datang untuk menyelamatkan ..
Sekali lagi Batman akan terlibat pertempuran, Robin akan tiba nanti.
Ini Batman:
+<FocusLock - enabled={componentControl.value} +> - {componentControl.value && <PageTitle title={componentControl.value.title}/>} + <DisplayData + data={componentControl.value} + visible={componentControl.value !== null} + /> +</FocusLock>
Ini adalah sahabat karibnya, Robin ::
-<FocusLock + enabled={componentControl.value} -> + {componentControl.value && <PageTitle title={componentControl.value.title}/>} - <DisplayData - data={componentControl.value} - visible={componentControl.value !== null} - /> -</FocusLock>
Batman dan Robin dapat membentuk TIM , tetapi mereka sebenarnya, adalah dua orang yang berbeda.
Dan jangan lupa - kita masih berbicara tentang pemecahan kode . Dan, dalam hal pemisahan kode, di mana sidekick itu? Dimana Robin?

di sespan. Robin sedang menunggu di bagian sespan .
Sespan
Batman
sini adalah semua barang visual yang harus dilihat pelanggan Anda sesegera mungkin. Idealnya secara instan.Robin
sini adalah semua logika, dan fitur interaktif yang mewah, yang mungkin tersedia setelah kedua, tetapi tidak di awal.
Akan lebih baik untuk menyebutnya pemisahan kode vertikal di mana cabang kode ada secara paralel, berlawanan dengan pemisahan kode horisontal umum di mana cabang kode dipotong .
Di beberapa negeri , trio ini dikenal sebagai replace reducer
atau cara lain untuk memuat logika reduks dan efek samping.
Di beberapa negara lain , ini dikenal sebagai "3 Phased" code splitting
.
Ini hanyalah pemisahan dari kekhawatiran, hanya berlaku untuk kasus, di mana Anda dapat menunda memuat beberapa bagian dari suatu komponen, tetapi bukan bagian lain.

gambar dari Membangun Facebook.com Baru dengan Bereaksi, GraphQL dan Relay , di mana importForInteractions
, atau importAfter
adalah sidecar
.
Dan ada pengamatan yang menarik - sementara Batman
lebih berharga untuk pelanggan, selama itu sesuatu yang mungkin dilihat pelanggan, dia selalu bugar ... Sementara Robin
, Anda tahu, dia mungkin sedikit kelebihan berat badan , dan membutuhkan lebih banyak byte untuk hidup.
Akibatnya - Batman sendiri adalah sesuatu yang jauh lebih bisa diterima oleh seorang pelanggan - ia memberikan nilai lebih dengan biaya lebih rendah. Anda adalah pahlawan saya Kelelawar!
Apa yang bisa dipindahkan ke sespan:
- mayoritas
useEffect
, componentDidMount
, dan teman-teman. - seperti semua efek Modal . Yakni
focus
dan scroll
kunci. Anda mungkin pertama kali menampilkan modal, dan baru kemudian membuat Modal modal , yaitu "mengunci" perhatian pelanggan. - Bentuk Memindahkan semua logika dan validasi ke sespan, dan memblokir pengiriman formulir sampai logika itu dimuat. Pelanggan bisa mulai mengisi formulir, tidak tahu bahwa itu hanya
Batman
. - Beberapa animasi. Seluruh
react-spring
dalam kasus saya. - Beberapa hal visual. Seperti bilah gulir Kustom , yang mungkin menampilkan bilah gulir mewah sedetik kemudian.
Juga, jangan lupa - Setiap bagian dari kode, diturunkan ke sespan, juga lepas dari hal-hal seperti core-js poly- dan ponyfill, yang digunakan oleh kode yang dihapus.
Pemecahan Kode bisa lebih pintar daripada yang ada di aplikasi kita hari ini. Kita harus menyadari ada 2 macam kode untuk dibagi: 1) aspek visual 2) aspek interaktif. Yang terakhir dapat datang beberapa saat kemudian. Sidecar
membuatnya mulus untuk membagi dua tugas, memberikan persepsi bahwa semuanya dimuat lebih cepat . Dan itu akan terjadi.
Cara terlama untuk memisahkan kode
Meskipun masih belum jelas kapan dan apa sidecar
, saya akan memberikan penjelasan sederhana:
Sidecar
adalah SEMUA TULISAN ANDA . Sidecar adalah cara kita menempatkan kode sebelum semua hal frontend yang kita dapatkan hari ini.
Saya berbicara tentang Server Side Rendering ( SSR ), atau hanya HTML biasa, kita semua terbiasa kemarin. Sidecar
membuat semuanya semudah dulu ketika halaman yang berisi HTML dan logika hidup terpisah dalam skrip eksternal yang dapat disematkan (pemisahan kekhawatiran).
Kami memiliki HTML, plus CSS, ditambah beberapa skrip yang diuraikan, ditambah skrip lainnya diekstraksi ke file .js
.
HTML
+ CSS
+ inlined-js
adalah Batman
, sedangkan skrip eksternal adalah Robin
, dan situs tersebut dapat berfungsi tanpa Robin, dan, jujur, sebagian tanpa Batman (ia akan melanjutkan pertarungan dengan kedua kaki (skrip inline) rusak). Itu baru kemarin, dan banyak situs "non modern dan keren" adalah sama hari ini.
Jika aplikasi Anda mendukung SSR - cobalah untuk menonaktifkan js dan membuatnya berfungsi tanpa itu. Maka akan menjadi jelas apa yang bisa dipindahkan ke sespan.
Jika aplikasi Anda hanya SPA sisi klien - coba bayangkan cara kerjanya, jika SSR ada.
Misalnya - theurge.com , ditulis dalam React, berfungsi penuh tanpa mengaktifkan js .
Ada banyak hal yang bisa Anda keluarkan ke sespan. Sebagai contoh:
- komentar. Anda mungkin mengirim kode untuk
display
komentar, tetapi tidak answer
, selama mungkin memerlukan lebih banyak kode (termasuk editor WYSIWYG), yang pada awalnya tidak diperlukan. Lebih baik menunda kotak komentar , atau bahkan hanya menyembunyikan pemuatan kode di balik animasi, daripada menunda seluruh halaman. - pemutar video. Kirimkan "video" tanpa "kontrol". Load mereka sedetik kemudian, mereka pelanggan mungkin mencoba untuk berinteraksi dengannya.
- galeri gambar, seperti
slick
. Ini bukan masalah besar untuk menggambarnya , tetapi jauh lebih sulit untuk menghidupkan dan mengelola. Jelas apa yang bisa dipindahkan ke sespan.
Pikirkan saja apa yang penting untuk aplikasi Anda, dan apa yang tidak cukup ...
Detail implementasi
(DI) Pemecahan kode komponen
Bentuk sidecar
paling sederhana adalah mudah diimplementasikan - cukup pindahkan semuanya ke sub komponen, Anda dapat memecah kode menggunakan cara "lama". Ini hampir merupakan pemisahan antara komponen Smart dan Dumb, tetapi kali ini Smart tidak memiliki komponen Dumb - justru sebaliknya.
const SmartComponent = React.lazy( () => import('./SmartComponent')); class DumbComponent extends React.Component { render() { return ( <React.Fragment> <SmartComponent ref={this} /> // <-- move smart one inside <TheActualMarkup /> // <-- the "real" stuff is here </React.Fragment> } }
Itu juga membutuhkan pemindahan kode inisialisasi ke kode Dumb, tetapi Anda masih dapat membagi kode bagian terberat dari suatu kode.
Bisakah Anda melihat pola pemisah kode parallel
atau vertical
sekarang?
useSidecar
Membangun Facebook.com Baru dengan React, GraphQL dan Relay , saya sudah sebutkan di sini, memiliki konsep loadAfter
atau importForInteractivity
, yang merupakan konsep sespan yang sangat mirip.
Pada saat yang sama, saya tidak akan merekomendasikan membuat sesuatu seperti useSidecar
selama Anda mungkin sengaja mencoba menggunakan hooks
di dalamnya, tetapi pemecahan kode dalam bentuk ini akan melanggar aturan kait .
Silakan pilih cara komponen yang lebih deklaratif. Dan Anda mungkin menggunakan hooks
di dalam komponen SideCar
.
const Controller = React.lazy( () => import('./Controller')); const DumbComponent = () => { const ref = useRef(); const state = useState(); return ( <> <Controller componentRef={ref} state={state} /> <TheRealStuff ref={ref} state={state[0]} /> </> ) }
Prefetching
Jangan lupa - Anda mungkin menggunakan petunjuk memuat prioritas untuk preload atau prefetch sidecar
dan membuatnya pengiriman lebih transparan dan tidak terlihat.
Hal-hal penting - skrip prefetching akan memuatnya melalui jaringan , tetapi tidak mengeksekusi (dan menghabiskan CPU) kecuali itu benar-benar diperlukan.
SSR
Tidak seperti pemisahan kode normal , tidak ada tindakan khusus yang diperlukan untuk SSR. Sidecar
mungkin bukan bagian dari proses SSR dan tidak diperlukan sebelum langkah hydration
. Itu bisa ditunda "oleh desain".
Dengan demikian - jangan ragu untuk menggunakan React.lazy
(idealnya sesuatu tanpa Suspense
, Anda tidak memerlukan indikator failback (memuat) di sini), atau pustaka lainnya, dengan, tetapi lebih baik tanpa dukungan SSR untuk melewati potongan sespan selama proses SSR.
Bagian yang buruk
Tetapi ada beberapa bagian buruk dari ide ini
Batman bukan nama produksi
Sementara Batman
/ Robin
mungkin konsep pikiran yang baik, dan sidecar
adalah pasangan yang sempurna untuk teknologi itu sendiri - tidak ada nama "baik" untuk maincar
. Tidak ada yang namanya maincar
, dan jelas Batman
, Lonely Wolf
, Solitude
, Driver
, dan Solo
tidak akan digunakan untuk menyebut bagian yang bukan sespan.
Facebook telah menggunakan display
dan interactivity
, dan itu mungkin pilihan terbaik bagi kita semua.
Jika Anda memiliki nama baik untuk saya - tinggalkan di komentar
Pohon bergetar
Ini lebih tentang pemisahan keprihatinan dari sudut pandang bundler . Bayangkan Anda memiliki Batman
dan Robin
. Dan stuff.js
Kemudian Anda dapat mencoba pemecahan kode komponen komponen untuk menerapkan sespan
Singkatnya - kode di atas akan berfungsi, tetapi tidak akan melakukan "pekerjaan".
- jika Anda hanya menggunakan
batman
dari stuff.js
- pohon goyang hanya akan menyimpannya. - jika Anda hanya menggunakan
robin
dari stuff.js
- gemetar pohon hanya akan membuatnya. - tetapi jika Anda menggunakan keduanya, bahkan dalam potongan yang berbeda - keduanya akan dibundel dalam kemunculan pertama
stuff.js
, yaitu bundel utama .
Mengguncang pohon tidak ramah pemecahan kode. Anda harus memisahkan masalah dengan file.
Batalkan impor
Hal lain, dilupakan oleh semua orang, adalah biaya javascript. Itu cukup umum di era jQuery, era payload jsonp
untuk memuat script (dengan payload json
), mendapatkan payload, dan menghapus script.
Saat ini kita semua import
skrip, dan itu akan selamanya diimpor, bahkan jika tidak lagi diperlukan.
Seperti yang saya katakan sebelumnya - ada terlalu banyak JS, dan cepat atau lambat, dengan navigasi terus menerus Anda akan memuat semuanya. Kita harus menemukan cara untuk membatalkan impor yang tidak perlu lagi dilakukan chunk, membersihkan semua cache internal dan membebaskan memori untuk membuat web lebih andal, dan tidak menghancurkan aplikasi tanpa pengecualian memori.
Mungkin kemampuan untuk un-import
(webpack dapat melakukannya ) adalah salah satu alasan kami harus tetap menggunakan API berbasis komponen , selama itu memberi kami kemampuan untuk menangani unmount
.
Sejauh ini - standar modul ESM tidak memiliki hal-hal seperti ini - atau tentang kontrol cache, atau tentang membalikkan tindakan impor.
Membuat Perpustakaan yang mendukung sespan
Sampai hari ini hanya ada satu cara untuk membuat pustaka yang diaktifkan sidecar
:
- pisahkan komponen Anda menjadi beberapa bagian
- mengekspos bagian
main
dan bagian yang connected
(tidak merusak API) melalui index
- mengekspos
sidecar
melalui titik masuk yang terpisah. - dalam kode target - impor bagian
main
dan sidecar
- goyangan pohon harus memotong bagian yang connected
.
Goyang pohon waktu ini harus bekerja dengan baik, dan satu-satunya masalah - adalah bagaimana menyebutkan bagian main
.
export const Main = ({sidecar, ...props}) => ( <div> {sidecar} .... </div> );
import Main from './Component'; import Sidecar from './Sidecar'; export const Connected = props => ( <Main sidecar={<Sidecar />} {...props} /> );
export * from './Main'; export * from './Connected';
import * from './Sidecar';
Singkatnya, perubahan dapat diwakili melalui perbandingan kecil
dynamic import
teoritis dapat digunakan di dalam node_modules, membuat proses assemble lebih transparan.
Pokoknya - itu tidak lebih dari pola children
- children
/ slot
, sangat umum di React.
Masa depan
Facebook
membuktikan bahwa idenya benar. Jika Anda belum melihat video itu - lakukan sekarang. Saya baru saja menjelaskan ide yang sama dari sudut yang sedikit berbeda (dan mulai menulis artikel ini seminggu sebelum konferensi F8).
Saat ini diperlukan beberapa perubahan kode untuk diterapkan ke basis kode Anda. Dibutuhkan pemisahan keprihatinan yang lebih eksplisit untuk benar-benar memisahkannya, dan membiarkan kode tidak diletakkan secara horizontal, tetapi secara vertikal, mengirimkan kode yang lebih kecil untuk pengalaman pengguna yang lebih besar .
Sidecar
, mungkin, adalah satu-satunya cara, kecuali SSR sekolah lama, untuk menangani basis kode BIG. Kesempatan terakhir untuk mengirimkan kode dalam jumlah minimal, ketika Anda memiliki banyak kode.
Itu bisa membuat aplikasi BESAR lebih kecil, dan aplikasi KECIL bahkan lebih kecil.
10 tahun yang lalu situs web medium "siap" dalam 300 ms, dan benar - benar siap beberapa milidetik setelahnya. Detik hari ini dan bahkan lebih dari 10 detik adalah angka umum. Sayang sekali.
Mari kita berhenti sejenak, dan berpikir - bagaimana kita bisa menyelesaikan masalah, dan membuat UX hebat lagi ...

Secara keseluruhan
- Pemecahan kode komponen adalah alat yang paling ampuh, memberi Anda kemampuan untuk benar - benar memecah sesuatu, tetapi ada biaya - Anda mungkin tidak menampilkan apa pun kecuali halaman kosong, atau kerangka untuk sementara waktu. Itu pemisahan horizontal.
- Pemisahan kode perpustakaan dapat membantu ketika pemisahan komponen tidak. Itu pemisahan horizontal.
- Kode, diturunkan ke sespan akan melengkapi gambar, dan mungkin membiarkan Anda memberikan pengalaman pengguna yang jauh lebih baik. Tetapi juga akan membutuhkan beberapa upaya rekayasa. Itu pemisahan vertikal.
Mari kita bicara tentang ini .
Berhenti! Jadi bagaimana dengan masalah yang Anda coba selesaikan?
Ya, itu baru bagian pertama. Kami berada di endgame sekarang , akan butuh beberapa minggu lagi untuk menuliskan bagian kedua dari proposal ini. Sementara itu ... dapatkan sespan!