Saya bertemu dengan pemecahan kode sejak lama, pada tahun 2008, ketika Yandex sedikit ditangguhkan, dan skrip Yandex.Direct yang terhubung secara sinkron ke situs hanya membunuh situs ini. Secara umum, itu normal pada hari-hari itu jika "skrip" Anda adalah 10 file yang Anda hubungkan dalam urutan yang benar, yang masih (dengan penundaan) masih berfungsi dengan baik.
Kemudian saya mulai bekerja secara aktif dengan kartu, dan mereka masih terhubung sebagai skrip eksternal, tentu saja malas-memuat. Kemudian, sebagai anggota tim Yandex.Mart, saya aktif menggunakan fitur pengocok pohon ymodules pada klien, yang memberikan pemecahan kode yang sempurna.
Dan kemudian saya pergi ke webpack
dan React
, ke negara orang-orang idiot yang ketakutan yang require.ensure
seperti seekor domba jantan di gerbang baru, dan masih melakukannya.
Pemecahan kode bukan fitur wow, itu harus dimiliki. Namun SSR
tidak akan mengganggu ...

Pengantar kecil
Saat ini, ketika bundel bertambah gemuk setiap hari, pemecahan kode menjadi lebih penting dari sebelumnya. Pada awalnya, orang keluar dari situasi ini hanya dengan membuat titik masuk yang terpisah untuk setiap halaman aplikasi mereka, yang umumnya baik, tetapi itu tidak akan berfungsi untuk SPA.
Kemudian muncul fungsi require.ensure
, hari ini dikenal sebagai dynamic import
(hanya impor), di mana Anda dapat dengan mudah meminta modul, yang akan Anda terima sedikit kemudian.
Perpustakaan pertama tentang kasus ini untuk React adalah load-load , hype sekitar yang masih belum begitu jelas bagi saya, dan yang sudah mati (itu hanya berhenti untuk menyenangkan penulis).
Saat ini pilihan yang lebih “kurang resmi” adalah React.lazy
dan komponen yang dapat dimuat (hanya @loadable
), dan pilihan di antara mereka sudah jelas:
- React.lazy benar-benar tidak dapat SSR (Server Side Rendering), dari kata pada umumnya. Bahkan dalam tes, itu akan jatuh tanpa tarian khusus dengan rebana, seperti "janji sinkron".
- SSR yang dapat dimuat dapat, dan saat mendukung Suspense, tidak lebih buruk dari React.Lazy.
Khususnya, loadable mendukung pembungkus yang indah untuk memuat pustaka (loadable.lib, Anda dapat mengambil moment.js ke dalam React renderProp), dan membantu webpack di sisi server untuk mengumpulkan daftar skrip, gaya, dan sumber daya yang digunakan untuk prefetching (yang webpack sendiri tidak benar-benar tahu). Secara umum, baca dokumentasi resmi .
SSR
Secara umum, seluruh masalah ada di SSR. Untuk CSR (Client Side Render), baik React.lazy atau skrip kecil dengan 10 baris akan cocok - ini pasti akan cukup, dan tidak masuk akal untuk menghubungkan perpustakaan eksternal yang besar. Tetapi pada server ini tidak akan cukup. Dan jika Anda tidak benar-benar membutuhkan RSK, Anda dapat melewatkan membaca lebih lanjut. Anda tidak memiliki masalah yang perlu diselesaikan lama dan sulit.
SSR itu menyakitkan. Saya (dalam beberapa hal) adalah salah satu pengelola komponen yang dapat dimuat dan hanya mengerikan berapa banyak bug yang keluar dari tempat yang berbeda. Dan dengan setiap pembaruan, webpack terbang lebih banyak.
SSR + CSS
Sumber masalah yang lebih besar dengan SSR adalah CSS.
Jika Anda memiliki komponen yang ditata - itu tidak terlalu menyakitkan - mereka datang dengan transform-stream
yang dengan sendirinya akan menambahkan apa yang diperlukan untuk kode akhir. Hal utama adalah bahwa harus ada satu versi SC di mana-mana, jika tidak fokus tidak akan berfungsi - satu versi SC tidak akan dapat memberi tahu hal lain tentang dirinya sendiri, dan SC suka memperbanyak diri (periksa bundel Anda). Sejujurnya, justru karena keterbatasan inilah fokus biasanya gagal .
C emosi lebih sederhana - adaptor styled
mereka hanya meludahkan <style>
di depan komponen itu sendiri, dan masalahnya selesai. Sederhana, murah, dan ceria. Pada prinsipnya, ini sangat mobile-friendly, dan sangat mengoptimalkan tampilan pertama. Tapi sedikit merusak yang kedua. Dan secara pribadi, hati nurani saya tidak memungkinkan saya untuk gaya inline seperti itu.
Dengan CSS biasa (termasuk yang diperoleh dari berbagai perpustakaan CSS-in-JS dengan sihir berbeda) itu bahkan lebih mudah - ada informasi tentang mereka di kolom webpack, dan “diketahui” CSS mana yang perlu disambungkan.
Pesanan Koneksi
Di sini anjing mengubur dirinya sendiri. Kapan saya harus terhubung?
Arti pemecahan kode ramah SSR adalah bahwa sebelum memanggil ReactDOM.hydrate
Anda perlu mengunduh semua "komponen" yang sudah ada dalam respons server, tetapi skrip yang saat ini dimuat pada klien tidak mampu.
Oleh karena itu, semua perpustakaan menawarkan panggilan balik tertentu yang akan dipanggil ketika semua-semua-semua yang perlu dimuat, dan Anda dapat memulai otak . Ini adalah arti dari karya pustaka peletakan kode SSR.
JS dapat dimuat kapan saja, dan biasanya daftar mereka ditambahkan ke akhir HTML, tetapi CSS, sehingga tidak ada FOUC, harus ditambahkan ke awal.
Semua perpustakaan dapat melakukan ini untuk renderToString
lama, dan semua perpustakaan tidak dapat melakukan ini untuk renderToNodeStream
.
Tidak masalah jika Anda hanya memiliki JS (ini tidak terjadi), atau SC / Emosi (yang akan menambah sendiri). Tetapi - jika Anda memiliki "hanya CSS" - itu saja. Entah mereka pada akhirnya, atau mereka harus menggunakan renderToString
, atau buffering lainnya, yang akan memberikan penundaan TTFB (Time To First Byte) dan sedikit mengurangi rasa memiliki SSR ini secara umum.
Dan tentu saja - semua ini terkait dengan webpack dan tidak ada cara lain. Oleh karena itu, dengan segala hormat kepada Greg, penulis komponen yang dapat dimuat - saya mengusulkan untuk mempertimbangkan opsi lain.
Berikutnya adalah agenda tiga bagian, gagasan utamanya adalah melakukan sesuatu yang tidak terbunuh dan tidak bergantung pada bundler.
1. Bereaksi-Impor-Komponen
React-Imported-Component bukanlah "loader" yang buruk, dengan antarmuka yang kurang lebih standar, sangat mirip dengan komponen yang dapat dimuat, yang dapat SSR untuk semua yang bergerak.
Idenya sangat sederhana.
Tidak perlu stats.json
, beradaptasi untuk optimasi webpack (gabungan, atau kode umum) - Anda hanya perlu mencocokkan "label" dari satu impor di kunci dalam array dan impor lagi. Bagaimana itu akan dilakukan sebagai bagian dari bundler tertentu, berapa banyak file yang benar-benar akan diunduh dan dari mana bukan masalahnya.
Minus - awal pemuatan potongan "bekas" terjadi setelah memuat bundel utama, yang menyimpan pemetaan, yang sedikit "lambat" daripada dalam kasus komponen yang dapat dimuat, yang akan menambahkan informasi ini langsung ke HTML.
Ya, dengan CCS itu tidak berfungsi pada kata.
2. gaya yang digunakan
Tetapi gaya yang digunakan hanya bekerja dengan CSS, tetapi dalam banyak cara yang sama seperti komponen yang diimportasi-impor.
- memindai semua css (di direktori build)
- ingat di mana kelas yang didefinisikan
- memindai output renderToNodeStream (atau respons
renderToString
) - menemukan class = 'XXX', cocok dengan file dan meludahkannya dalam respons server.
- (well, lalu teleport semua gaya seperti itu ke kepala agar tidak merusak hidrat). Komponen Style berfungsi sama.
Tidak ada penundaan TTBT, itu tidak terikat pada bundler - dongeng. Bekerja seperti arloji jika gaya ditulis dengan baik.
Bereaksi-impor-komponen + gaya-pakai + contoh kerja parcel .
Bukan bonus yang paling jelas - di server, kedua perpustakaan akan melakukan "semua yang diperlukan" selama startup, sampai server ekspres dapat menerima klien pertama, dan akan sepenuhnya disinkronkan baik di server dan selama pengujian.
3. komponen reaksi-prerender
Dan perpustakaan menutup tiga teratas, yang melakukan "rehidrasi parsial" , dan melakukannya dengan cara kakek sehingga saya langsung bertanya-tanya. Dia benar-benar menambahkan "diva."
- di server:
- membungkus sepotong kayu di div dengan "id terkenal"
- pada klien:
- konstruktor komponen menemukan div sendiri
- menyalin innerHTML-nya sebelum React mengambilnya.
- menggunakan HTML ini sampai klien siap untuk
hydrate
- secara teknis, ini memungkinkan penggunaan Hybrid SSR (Rendertron)
const AsyncLoadedComponent = loadable(() => import('./deferredComponent')); const AsyncLoadedComponent = imported(() => import('./deferredComponent')); <PrerenderedComponent live={AsyncLoadedComponent.preload()} // when Promise got resolve - component will go "live" > <AsyncLoadedComponent /> // meanwhile you will see "preexisting" content </PrerenderedComponent>
Fokus ini tidak berfungsi dengan komponen yang dapat dimuat, karena tidak kembali dari janji preload . Ini sangat penting untuk perpustakaan seperti react-snap (dan "prerender" lainnya) yang memiliki "konten" tetapi belum melewati SSR "nyata".

Dari sudut pandang kode, ini adalah 10 baris, ditambah sedikit lagi untuk mendapatkan UID SSR-CSR yang stabil dengan mempertimbangkan urutan acak pemuatan dan pelaksanaan kode.
Bonus:
- Anda tidak perlu menunggu "pemuatan semua skrip" sebelum memulai otak - otak akan mulai saat siap
- Anda tidak perlu memuat otak sama sekali, meninggalkan data SSR-ed (jika tidak ada versi SSR maka otak akan tetap dimuat). Sama seperti di jQuery kali.
- Anda juga dapat menerapkan aliran caching dari blok render besar (kompatibel dengan Suspensi secara teoritis) - lagi menggunakan transform stream.
- dan serialisasi / deserializing negara ke / dari HTML, seperti selama jQuery
Pada prinsipnya, serialisasi dan deserialisasi adalah ide utama membuat perpustakaan untuk memecahkan masalah duplikasi negara (gambar dari artikel tentang SSR). Caching tiba kemudian.

Total
Secara total, ada tiga pendekatan yang dapat mengubah pandangan Anda tentang SSR dan pemecahan kode. Yang pertama bekerja dengan menempatkan kode JS, dan tidak pecah. Yang kedua bekerja dengan menempatkan kode CSS, dan tidak rusak. Yang ketiga bekerja di level HTML menyederhanakan dan mempercepat beberapa proses, dan sekali lagi, itu tidak rusak.
Tautan ke perpustakaan:
Artikel (dalam bahasa Inggris)