Hari ini kami menerbitkan terjemahan cerita tentang bagaimana transisi dari
React Boilerplate ke
Next.js , sebuah kerangka kerja untuk mengembangkan aplikasi web progresif berdasarkan React, telah mempercepat pemuatan
beranda situs proyek manifold.co 7,5 kali. Tidak ada perubahan lain yang dilakukan pada proyek, dan transisi ini, secara umum, ternyata sama sekali tidak terlihat oleh bagian lain dari sistem. Apa yang ternyata pada akhirnya ternyata lebih baik dari yang diharapkan.

Ikhtisar Hasil
Bahkan, kita dapat mengatakan bahwa transisi ke Next.js memberi kita sesuatu seperti "peningkatan produktivitas proyek yang muncul entah dari mana". Beginilah tampilan waktu proyek ketika menggunakan berbagai sumber daya perangkat keras dan koneksi jaringan.
Koneksi
| CPU
| Ke detik
| Setelah beberapa detik
| % Peningkatan
|
Cepat (200 Mbps)
| Cepat
| 1.5
| 0,2
| 750
|
Sedang (3G)
| Cepat
| 5.6
| 1.1
| 500
|
Sedang (3G)
| Sedang
| 7.5
| 1.3
| 570
|
Lambat (koneksi 3G lambat)
| Sedang
| 22
| 4
| 550
|
Saat menggunakan koneksi cepat dan perangkat dengan prosesor cepat, waktu muat situs turun dari 1,5 detik. hingga 0,2 s., yaitu, indikator ini meningkat 7,5 kali. Pada koneksi berkualitas menengah dan pada perangkat dengan kinerja rata-rata, waktu muat situs turun dari 7,5 detik. hingga 1,3 dtk
Apa yang terjadi setelah pengguna mengklik URL?
Untuk memahami fitur-fitur dari pekerjaan aplikasi web progresif (Progressive Web App, PWA), pertama-tama Anda perlu mencari tahu apa yang terjadi antara saat ketika pengguna mengklik URL (di alamat situs kami) dan saat ketika ia melihat sesuatu. di jendela browser (dalam hal ini, aplikasi Bereaksi kami).
Tahapan AplikasiPertimbangkan 5 tahapan bekerja dengan aplikasi, diagram yang diberikan di atas.
- Pengguna pergi ke URL, sistem mengetahui alamat server menggunakan DNS dan mengakses server. Semua ini dilakukan dengan sangat cepat, biasanya memakan waktu kurang dari 100 milidetik, tetapi langkah ini membutuhkan waktu, itulah sebabnya disebutkan di sini.
- Sekarang server mengembalikan kode HTML halaman, tetapi halaman di browser tetap kosong sampai sumber daya yang diperlukan untuk tampilan dimuat (kecuali sumber daya dimuat secara tidak sinkron ). Sebenarnya, lebih banyak tindakan yang terjadi pada tahap ini daripada yang ditunjukkan dalam diagram, tetapi tinjauan bersama dari semua proses ini juga akan cocok untuk kita.
- Setelah memuat kode HTML dan sumber daya yang paling penting, browser mulai menampilkan apa yang dapat ditampilkannya, terus memuat yang lainnya (gambar, misalnya) di latar belakang. Pernahkah Anda bertanya-tanya mengapa gambar kadang-kadang tiba-tiba "muncul" pada halaman jelas lebih cepat dari yang diperlukan, dan kadang-kadang memuat terlalu lama? Inilah mengapa ini terjadi. Pendekatan ini memungkinkan Anda membuat halaman selesai dengan cepat.
- Kode JavaScript dapat diuraikan dan dieksekusi hanya setelah dimuat. Bergantung pada ukuran kode JS yang digunakan pada halaman (dan ini mungkin, untuk aplikasi Bereaksi khas, cukup besar jika kode tersebut dikemas dalam satu file) mungkin perlu beberapa detik atau bahkan lebih (perhatikan bahwa JS kode tidak perlu, untuk mulai mengeksekusi, tunggu pemuatan semua sumber daya lainnya, meskipun pada diagram terlihat persis seperti itu).
- Dalam kasus aplikasi Bereaksi, momen sekarang datang ketika kode memodifikasi DOM, yang menyebabkan browser untuk menggambar kembali halaman yang sudah ditampilkan. Kemudian siklus pemuatan sumber daya lain dimulai. Waktu yang dibutuhkan langkah ini akan tergantung pada kompleksitas halaman.
Semakin cepat, semakin baik.
Karena aplikasi web progresif mengambil kode Bereaksi dan menghasilkan kode HTML dan CSS statis, ini berarti bahwa pengguna melihat aplikasi Bereaksi sudah pada langkah 3 dari skema di atas, dan bukan pada langkah 5. Dalam pengujian kami, ini membutuhkan 0,2-4 detik , yang tergantung pada kecepatan koneksi pengguna ke Internet dan perangkatnya. Ini jauh lebih baik daripada 1,5-22 detik sebelumnya. Aplikasi web progresif adalah cara yang andal untuk mengirimkan aplikasi Bereaksi lebih cepat kepada pengguna.
Alasan bahwa aplikasi web progresif dan kerangka kerja terkait seperti Next.js masih belum begitu populer adalah karena, secara tradisional, kerangka kerja JS tidak terlalu berhasil dalam menghasilkan kode HTML statis. Hari ini, semuanya telah banyak berubah karena fakta bahwa kerangka kerja seperti React, Vue dan Angular, dan lainnya, memiliki dukungan yang sangat baik untuk rendering sisi server. Namun, untuk menggunakan alat-alat ini, Anda masih membutuhkan pemahaman yang mendalam tentang fitur-fitur karya bundler dan alat untuk membangun proyek. Bekerja dengan semua ini bukan tanpa masalah.
Munculnya kerangka kerja PWA baru-baru ini seperti Next.js dan Gatsby (keduanya muncul pada akhir 2016 - awal 2017) adalah langkah serius menuju adopsi PWA yang luas karena hambatan masuk yang lebih rendah dan karena fakta bahwa kerangka kerja tersebut menggunakan tugas tersebut sebagai tugas yang sederhana dan menyenangkan.
Meskipun tidak setiap aplikasi dapat ditransfer ke Next.js, untuk banyak aplikasi Bereaksi transisi ini berarti "kinerja entah dari mana" yang kita bicarakan di sini, ditambah dengan penggunaan sumber daya jaringan yang bahkan lebih efisien.
Seberapa sulitkah untuk bermigrasi ke Next.js?
Secara umum, dapat dicatat bahwa menerjemahkan beranda kami ke Next.js tidak terlalu sulit. Namun, kami menemui beberapa kesulitan yang disebabkan oleh fitur arsitektur aplikasi kami.
β Menolak React Router
Kami harus meninggalkan router React karena Next.js memiliki router bawaannya sendiri, yang lebih baik dikombinasikan dengan optimisasi mengenai pemisahan kode yang dilakukan di atas arsitektur PWA. Ini memungkinkan router ini untuk menyediakan pemuatan halaman yang jauh lebih cepat daripada yang Anda harapkan dari router sisi klien mana pun.
Router Next.js adalah sedikit router React berkecepatan tinggi, tetapi masih bukan router React.
Dalam praktiknya, karena kami tidak memanfaatkan fitur-fitur canggih yang ditawarkan router React, transisi ke router Next.js bagi kami adalah dengan hanya mengganti komponen router React standar dengan komponen Next.js yang sesuai:
/* ( React) */ <Link to="/my/page"> A link </Link> /* ( Next.js) */ <Link href="/my/page" passHref> <a> A link </a> </Link>
Secara umum, semuanya ternyata tidak terlalu buruk. Kami harus mengubah nama properti dan menambahkan tag untuk keperluan rendering server. Karena kami juga menggunakan pustaka
styled-components
, ternyata dalam sebagian besar kasus kami perlu menambahkan properti
passHref
untuk memastikan bahwa sistem berperilaku sedemikian rupa sehingga
href
selalu menunjuk ke tag yang dihasilkan.
Permintaan Jaringan untuk manifold.coUntuk melihat dengan optimalisasi router Next.js dengan mata kepala Anda sendiri, buka tab Network dari alat pengembang browser dengan melihat halaman
manifold.co dan klik pada beberapa tautan. Gambar sebelumnya menunjukkan hasil mengklik tautan
/services
. Seperti yang Anda lihat, ini mengarah pada eksekusi permintaan untuk memuat
services.js
alih-alih mengeksekusi permintaan biasa.
Saya tidak hanya berbicara tentang perutean sisi klien, router Bereaksi juga cocok untuk menyelesaikan masalah ini. Saya sedang berbicara tentang bagian nyata dari kode JavaScript yang telah diekstraksi dari sisa kode dan dimuat berdasarkan permintaan. Ini dilakukan dengan menggunakan Next.js. standar Dan ini jauh lebih baik daripada yang kita miliki sebelumnya. Yaitu, kita berbicara tentang paket besar kode JS dengan ukuran 1,7 MB, yang klien, sebelum dia bisa melihat sesuatu, harus mengunduh dan memproses.
Meskipun solusi yang disajikan di sini tidak sempurna, itu jauh lebih dekat daripada yang sebelumnya dengan gagasan bahwa pengguna hanya mengunduh kode untuk halaman yang mereka lihat.
β Fitur menggunakan Redux
Melanjutkan topik kesulitan yang terkait dengan transisi ke Next.js, dapat dicatat bahwa semua optimasi menarik yang dilakukan Next.js terhadap aplikasi memiliki dampak tertentu pada aplikasi ini. Yaitu, karena Next.js melakukan pemisahan kode tingkat halaman, itu mencegah pengembang mengakses komponen
React
root atau metode
render()
dari perpustakaan
react-dom
. Jika Anda telah terlibat dalam mengonfigurasi Redux, maka Anda dapat mencatat bahwa semua ini memberi tahu kami bahwa untuk operasi normal dengan Redux kita perlu menyelesaikan masalah, yaitu bahwa tidak jelas di mana tepatnya mencari Redux.
Next.js menyediakan komponen tingkat tinggi khusus,
withRedux
, yang
withRedux
sebagai pembungkus untuk semua komponen tingkat atas pada setiap halaman:
export default withRedux(HomePage);
Meskipun semua ini tidak terlalu buruk, tetapi jika Anda memerlukan metode
createStore()
, seperti ketika menggunakan
redux-reducer-injectors , harap Anda perlu waktu ekstra untuk men-debug pembungkus (dan omong-omong, jangan pernah mencoba gunakan sesuatu seperti
redux-reducer-injectors
).
Selain itu, karena fakta bahwa Redux sekarang menjadi "kotak hitam", menggunakan perpustakaan
Immutable dengan itu menjadi bermasalah. Meskipun fakta bahwa Immutable akan bekerja dengan Redux tampaknya cukup jelas, saya mengalami masalah. Jadi, baik tingkat atas tidak berubah (
get is not a function
kesalahan
get is not a function
), atau komponen pembungkus mencoba menggunakan notasi titik untuk bekerja dengan objek JS bukannya metode
.get()
(
Can't get catalog of undefined
kesalahan yang
Can't get catalog of undefined
). Untuk men-debug masalah ini, saya harus merujuk ke kode sumber. Bagaimanapun, Next.js memaksa pengembang untuk menggunakan mekanisme sendiri karena suatu alasan.
Secara umum, dapat dicatat bahwa masalah utama yang terkait dengan Next.js adalah sangat sedikit dalam kerangka kerja ini yang terdokumentasi dengan baik. Ada banyak contoh dalam
dokumentasi dengan dasar di mana Anda dapat membuat sesuatu sendiri, tetapi jika di antara mereka tidak ada yang mencerminkan fitur-fitur proyek Anda, Anda hanya bisa berharap keberuntungan.
β Ambil penolakan
Kami menggunakan
pustaka react-inlinesvg , yang menawarkan opsi gaya untuk gambar SVG tertanam dan caching permintaan. Tapi di sini kami punya satu masalah: ketika melakukan rendering server, tidak ada yang namanya permintaan XHR (setidaknya tidak dalam arti URL yang dihasilkan oleh Webpack, seperti yang Anda harapkan). Upaya untuk mengeksekusi permintaan tersebut mengganggu rendering server.
Meskipun ada perpustakaan lain untuk bekerja dengan data SVG tertanam yang mendukung SSR, saya memutuskan untuk meninggalkan fitur ini, karena file SVG masih jarang digunakan. Saya menggantinya dengan gambar biasa,
<img>
, jika saya tidak perlu penataan saat menampilkan gambar yang sesuai, atau saya menyematkannya ke dalam kode dalam bentuk React JSX. Mungkin, semuanya menjadi lebih baik, karena ilustrasi JSX sekarang mengenai browser ketika halaman pertama kali dimuat dan bundel JS yang dikirim ke klien memiliki 1 perpustakaan lebih sedikit.
Jika Anda perlu menggunakan mekanisme pemuatan data (saya membutuhkan fitur ini untuk pustaka lain), maka Anda dapat mengonfigurasi ini menggunakan
next.config.js
, menggunakan
whatwg-fetch
dan
node-fetch
:
module.exports = { webpack: (config, options) => Object.assign(config, { plugins: config.plugins.concat([ new webpack.ProvidePlugin( config.isServer ? {} : { fetch: 'imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch' } ), ]), resolve: Object.assign(config.resolve, { alias: Object.assign( config.resolve.alias, config.isServer ? {} : { fetch: 'node-fetch' } ), }), }), };
β JS klien dan server
Fitur terakhir Next.js, yang ingin saya sebutkan di sini, adalah bahwa kerangka kerja ini diluncurkan dua kali - sekali untuk server, dan sekali lagi untuk klien. Ini sedikit mengaburkan garis antara sisi klien JavaScript dan kode Node.js dalam basis kode yang sama, menyebabkan kesalahan yang tidak biasa seperti
fs is undefined
ketika mencoba memanfaatkan fitur Node.js pada klien.
Akibatnya, kita harus membuat konstruksi seperti itu di
next.js.config
:
module.exports = { webpack: (config, options) => Object.assign(config, { node: config.isServer ? undefined : { fs: 'empty' }, }), };
Bendera
config.isServer
di Webpack akan menjadi teman terbaik Anda jika Anda perlu menjalankan kode yang sama di lingkungan yang berbeda.
Selain itu, Next.js mendukung, di samping metode standar untuk siklus hidup komponen Bereaksi, metode
getInitialProps()
, yang dipanggil hanya ketika kode
getInitialProps()
dalam mode server:
class HomePage extends React.Component { static getInitialProps() { // } componentDidMount() { // , } β¦ }
Ya, dan jangan lupa bahwa teman baik kita, objek
window
, yang diperlukan untuk mengatur acara mendengarkan, untuk menentukan ukuran jendela browser dan memberikan akses ke banyak fungsi yang bermanfaat, tidak tersedia di Node.js:
if (typeof window !== 'undefined') { // , `window` }
Perlu dicatat bahwa bahkan Next.js tidak dapat menyelamatkan pengembang dari kebutuhan untuk menyelesaikan masalah yang terkait dengan pelaksanaan kode yang sama di server dan di klien. Tetapi ketika memecahkan masalah seperti itu,
config.isServer
dan
getInitialProps()
sangat berguna.
Hasil: apa yang akan terjadi setelah Next.js?
Dalam jangka pendek, kerangka Next.js sangat cocok, dalam hal kinerja, persyaratan kami untuk rendering server dan kemampuan untuk melihat situs kami di perangkat yang menonaktifkan JavaScript. Selain itu, sekarang Anda dapat menggunakan
tag meta lanjutan (kaya).
Mungkin di masa depan kami akan mempertimbangkan opsi lain jika aplikasi kami membutuhkan server rendering dan logika server yang lebih kompleks (misalnya, kami melihat kemungkinan penerapan teknologi akses tunggal di manifold.co dan dashboard.manifold.co ) Tetapi sampai saat itu kita akan menggunakan Next.js, karena kerangka kerja ini, dengan biaya waktu yang kecil, membawa kita banyak manfaat.
Pembaca yang budiman! Apakah Anda menggunakan Next.js dalam proyek Anda?
