Transcript

00:00:00(musik ceria) - Oke, terima kasih semuanya, halo.
00:00:07Nama saya Luke Sandberg.
00:00:09Saya seorang insinyur perangkat lunak di Vercel,
00:00:11mengerjakan Turbo Pack.
00:00:12Saya sudah di Vercel sekitar enam bulan,
00:00:14waktu yang cukup bagi saya untuk naik ke panggung ini dan menceritakan semua pekerjaan hebat yang tidak saya lakukan.
00:00:23Sebelum di Vercel,
00:00:24saya di Google,
00:00:25mengerjakan rantai alat web internal kami dan melakukan hal-hal aneh seperti membuat kompilator kode byte TSX ke Java dan mengerjakan kompilator closure.
00:00:37Jadi,
00:00:37saat saya tiba di Vercel,
00:00:40rasanya seperti menginjak planet lain,
00:00:43semuanya berbeda.
00:00:45Saya cukup terkejut dengan semua yang kami lakukan di tim dan tujuan yang kami miliki.
00:00:50Hari ini saya akan berbagi beberapa pilihan desain yang kami buat di Turbo Pack dan bagaimana menurut saya itu akan memungkinkan kami terus membangun performa fantastis yang sudah kami miliki.
00:01:01Untuk memotivasi hal itu, inilah tujuan desain utama kami.
00:01:06Dari sini,
00:01:06Anda bisa langsung menyimpulkan bahwa kami mungkin membuat beberapa pilihan sulit.
00:01:14Jadi, bagaimana dengan 'cold build'?
00:01:17Itu penting,
00:01:18tapi salah satu ide kami adalah Anda seharusnya tidak mengalaminya sama sekali.
00:01:22Dan itulah yang akan menjadi fokus pembicaraan ini.
00:01:24Dalam pidato utama,
00:01:25Anda mendengar sedikit tentang bagaimana kami memanfaatkan inkrementalitas untuk meningkatkan performa bundling.
00:01:31Ide utama kami untuk inkrementalitas adalah tentang caching.
00:01:35Kami ingin membuat setiap hal yang dilakukan bundler bisa di-cache,
00:01:38sehingga setiap kali Anda membuat perubahan,
00:01:40kami hanya perlu mengulang pekerjaan yang terkait dengan perubahan itu.
00:01:43Atau mungkin dengan kata lain,
00:01:45biaya build Anda seharusnya benar-benar sebanding dengan ukuran atau kompleksitas perubahan Anda,
00:01:50bukan ukuran atau kompleksitas aplikasi Anda.
00:01:53Dan inilah cara kami memastikan bahwa Turbo Pack akan terus memberikan performa yang baik kepada pengembang,
00:01:58tidak peduli berapa banyak pustaka ikon yang Anda impor.
00:02:01Jadi,
00:02:02untuk membantu memahami dan memotivasi ide itu,
00:02:04mari kita bayangkan bundler paling sederhana di dunia,
00:02:07yang mungkin terlihat seperti ini.
00:02:09Jadi, inilah bundler 'bayi' kami.
00:02:12Dan ini mungkin terlalu banyak kode untuk diletakkan di slide,
00:02:15tapi akan lebih buruk lagi.
00:02:17Jadi di sini kami mengurai setiap titik masuk.
00:02:20Kami mengikuti impornya,
00:02:21menyelesaikan referensinya,
00:02:23secara rekursif di seluruh aplikasi untuk menemukan semua yang Anda andalkan.
00:02:28Kemudian pada akhirnya,
00:02:29kami hanya mengumpulkan semua yang diandalkan setiap titik masuk dan menempatkannya ke dalam file keluaran.
00:02:35Hore, kami punya bundler 'bayi'.
00:02:38Jadi jelas ini naif,
00:02:39tapi jika kita memikirkannya dari perspektif inkremental,
00:02:42tidak ada bagian dari ini yang inkremental.
00:02:45Jadi kami pasti akan mengurai file-file tertentu,
00:02:48berkali-kali,
00:02:49mungkin tergantung berapa kali Anda mengimpornya,
00:02:52itu mengerikan.
00:02:53Kami pasti akan menyelesaikan impor React ratusan atau ribuan kali.
00:02:57Jadi, aduh.
00:03:01Jadi jika kita ingin ini sedikit lebih inkremental,
00:03:04kita perlu menemukan cara untuk menghindari pekerjaan yang berlebihan.
00:03:08Jadi mari kita tambahkan cache.
00:03:10Jadi Anda mungkin membayangkan ini adalah fungsi parse kami.
00:03:15Ini cukup sederhana.
00:03:15Dan ini mungkin semacam 'kuda pekerja' bundler kami.
00:03:19Sangat sederhana.
00:03:19Kami membaca isi file,
00:03:21menyerahkannya ke SWC untuk memberi kami AST.
00:03:25Jadi mari kita tambahkan cache.
00:03:27Oke,
00:03:27jadi ini jelas merupakan kemenangan sederhana yang bagus.
00:03:31Tapi,
00:03:32saya yakin beberapa dari Anda pernah menulis kode caching sebelumnya.
00:03:36Mungkin ada beberapa masalah di sini.
00:03:38Misalnya, bagaimana jika file berubah?
00:03:41Ini jelas sesuatu yang kami pedulikan.
00:03:46Dan,
00:03:46bagaimana jika file itu sebenarnya bukan file,
00:03:49melainkan tiga symlink dalam kode yang rumit?
00:03:52Banyak manajer paket akan mengatur dependensi seperti itu.
00:03:55Dan kami menggunakan nama file sebagai kunci cache.
00:03:59Apakah itu cukup?
00:04:00Misalnya, kami melakukan bundling untuk klien dan server.
00:04:03File yang sama berakhir di keduanya.
00:04:04Apakah itu berhasil?
00:04:05Kami juga menyimpan AST dan mengembalikannya.
00:04:08Jadi sekarang kita harus khawatir tentang mutasi.
00:04:11Jadi,
00:04:11dan terakhir,
00:04:12bukankah ini cara mengurai yang sangat naif?
00:04:16Saya tahu bahwa setiap orang memiliki konfigurasi besar untuk kompilator.
00:04:21Beberapa di antaranya harus masuk ke sini.
00:04:23Jadi, ya, ini semua adalah umpan balik yang bagus.
00:04:27Dan ini adalah pendekatan yang sangat naif.
00:04:32Dan untuk itu,
00:04:33tentu saja,
00:04:33saya akan mengatakan,
00:04:34ya,
00:04:35ini tidak akan berhasil.
00:04:36Jadi apa yang kita lakukan untuk memperbaiki masalah ini?
00:04:39Tolong perbaiki dan jangan membuat kesalahan.
00:04:44Jadi, oke.
00:04:46Jadi mungkin ini sedikit lebih baik.
00:04:49Anda bisa lihat di sini bahwa kami memiliki beberapa transformasi.
00:04:52Kita perlu melakukan hal-hal yang disesuaikan untuk setiap file,
00:04:55seperti mungkin 'down-leveling' atau mengimplementasikan 'use cache'.
00:04:58Kami juga memiliki beberapa konfigurasi.
00:05:00Dan tentu saja,
00:05:01kita perlu menyertakannya dalam kunci untuk cache kita.
00:05:04Tapi mungkin Anda langsung curiga.
00:05:08Misalnya, apakah ini benar?
00:05:09Misalnya,
00:05:10apakah cukup untuk mengidentifikasi transformasi berdasarkan nama?
00:05:13Saya tidak tahu,
00:05:14mungkin itu memiliki konfigurasi rumitnya sendiri.
00:05:16Dan,
00:05:17oke,
00:05:17dan apakah nilai JSON ini benar-benar akan menangkap semua yang kita pedulikan?
00:05:24Apakah pengembang akan memeliharanya?
00:05:26Seberapa besar kunci cache ini?
00:05:29Berapa banyak salinan konfigurasi yang akan kita miliki?
00:05:31Saya pribadi pernah melihat kode persis seperti ini,
00:05:34dan saya merasa hampir mustahil untuk memahaminya.
00:05:37Oke,
00:05:37kami juga mencoba memperbaiki masalah lain seputar invalidasi.
00:05:43Jadi kami menambahkan API callback untuk membaca file.
00:05:46Ini bagus,
00:05:47jadi jika file berubah,
00:05:48kita bisa langsung menghapusnya dari cache,
00:05:51agar kita tidak terus menyajikan konten yang usang.
00:05:55Oke,
00:05:55tapi ini sebenarnya cukup naif,
00:05:57karena,
00:05:57tentu saja,
00:05:58kita perlu menghapus cache kita,
00:05:59tapi pemanggil kita juga perlu tahu bahwa mereka perlu mendapatkan salinan baru.
00:06:03Jadi, oke, mari kita mulai menjalin callback.
00:06:06Oke, kami berhasil.
00:06:09Kami menjalin callback ke atas melalui stack.
00:06:12Anda bisa lihat di sini bahwa kami mengizinkan pemanggil kami untuk berlangganan perubahan.
00:06:16Kita bisa saja menjalankan ulang seluruh bundle jika ada yang berubah,
00:06:20dan jika file berubah,
00:06:21kita memanggilnya.
00:06:22Bagus, kami punya bundler reaktif.
00:06:25Tapi ini masih jauh dari inkremental.
00:06:28Jadi jika file berubah,
00:06:30kita perlu menelusuri semua modul lagi dan menghasilkan semua file keluaran.
00:06:37Jadi,
00:06:38kami menghemat banyak pekerjaan dengan memiliki cache parse kami,
00:06:43tapi ini sebenarnya tidak cukup.
00:06:45Dan kemudian akhirnya,
00:06:47ada semua pekerjaan berlebihan lainnya ini.
00:06:49Misalnya, kami pasti ingin menyimpan cache impor.
00:06:52Kita mungkin menemukan file berkali-kali,
00:06:53dan kita terus membutuhkan impornya,
00:06:55jadi kita ingin menempatkan cache di sana.
00:06:57Dan,
00:06:58hasil resolusi sebenarnya cukup rumit,
00:07:00jadi kita harus menyimpan cache itu agar kita bisa menggunakan kembali pekerjaan yang kita lakukan dalam menyelesaikan React.
00:07:08Tapi, oke, sekarang kita punya masalah lain.
00:07:11Hasil resolusi Anda berubah saat Anda memperbarui dependensi atau menambahkan file baru,
00:07:16jadi kita butuh callback lain di sana.
00:07:18Dan kami juga pasti ingin menyimpan cache logika untuk menghasilkan keluaran karena jika Anda memikirkannya dalam sesi HMR,
00:07:25Anda mengedit satu bagian aplikasi,
00:07:27jadi mengapa kita menulis ulang semua keluaran setiap saat?
00:07:31Dan juga,
00:07:32Anda mungkin menghapus file keluaran,
00:07:34jadi kita mungkin harus mendengarkan perubahan di sana juga.
00:07:39Oke,
00:07:39jadi mungkin kita sudah menyelesaikan semua hal itu,
00:07:42tapi kita masih punya masalah ini,
00:07:44yaitu setiap kali ada yang berubah,
00:07:46kita mulai dari awal.
00:07:48Jadi,
00:07:48alur kontrol keseluruhan fungsi ini tidak berfungsi karena jika satu file berubah,
00:07:53kita sebenarnya ingin melompat ke tengah-tengah perulangan 'for' itu.
00:07:56Dan kemudian,
00:07:58akhirnya,
00:07:58API kami kepada pemanggil kami juga sangat naif.
00:08:03Mereka mungkin sebenarnya ingin tahu file mana yang berubah,
00:08:05sehingga mereka bisa,
00:08:06misalnya,
00:08:06mendorong pembaruan ke klien.
00:08:07Jadi, ya.
00:08:11Jadi, pendekatan ini tidak benar-benar berhasil.
00:08:13Dan bahkan jika kita entah bagaimana berhasil menjalin semua callback di semua tempat ini,
00:08:18apakah Anda pikir Anda benar-benar bisa memelihara kode ini?
00:08:21Apakah Anda pikir Anda bisa,
00:08:22misalnya,
00:08:23menambahkan fitur baru ke dalamnya?
00:08:24Saya tidak berpikir begitu.
00:08:25Saya pikir ini akan langsung gagal total.
00:08:28Dan, Anda tahu, untuk itu, saya akan mengatakan, ya.
00:08:34Jadi, sekali lagi, apa yang harus kita lakukan?
00:08:36Anda tahu,
00:08:37sama seperti saat Anda mengobrol dengan LLM,
00:08:40Anda sebenarnya perlu tahu dulu apa yang Anda inginkan.
00:08:43Dan kemudian Anda harus sangat jelas tentang hal itu.
00:08:48Jadi, apa sebenarnya yang kita inginkan?
00:08:50Jadi,
00:08:50kami mempertimbangkan banyak pendekatan berbeda,
00:08:53dan banyak orang di tim sebenarnya memiliki banyak pengalaman mengerjakan bundler.
00:08:59Jadi, kami menghasilkan semacam persyaratan kasar ini.
00:09:02Jadi,
00:09:02kami pasti ingin bisa menyimpan cache setiap operasi yang mahal di bundler.
00:09:05Dan ini seharusnya sangat mudah dilakukan.
00:09:08Misalnya,
00:09:09Anda seharusnya tidak mendapatkan 15 komentar pada tinjauan kode Anda setiap kali Anda menambahkan cache baru.
00:09:12Dan kemudian saya sebenarnya tidak terlalu percaya pengembang untuk menulis kunci cache yang benar atau melacak masukan atau melacak dependensi secara manual.
00:09:24Jadi, kami harus menanganinya.
00:09:26Kita harus benar-benar membuatnya 'anti-gagal'.
00:09:30Selanjutnya, kita perlu menangani masukan yang berubah.
00:09:33Ini seperti ide besar dalam HMR,
00:09:34tapi bahkan di seluruh sesi.
00:09:36Jadi,
00:09:36sebagian besar ini akan berupa file,
00:09:38tapi ini juga bisa berupa hal-hal seperti pengaturan konfigurasi.
00:09:40Dan dengan cache sistem file,
00:09:41ini sebenarnya juga berakhir menjadi hal-hal seperti variabel lingkungan.
00:09:45Jadi, kami ingin menjadi reaktif.
00:09:47Kami ingin dapat menghitung ulang hal-hal segera setelah ada yang berubah,
00:09:51dan kami tidak ingin menjalin callback di mana-mana.
00:09:54Akhirnya,
00:09:55kita hanya perlu memanfaatkan arsitektur modern dan menjadi multi-threaded serta secara umum cepat.
00:10:02Jadi,
00:10:03mungkin Anda melihat serangkaian persyaratan ini,
00:10:07dan beberapa dari Anda berpikir,
00:10:09apa hubungannya ini dengan bundler?
00:10:12Dan untuk itu,
00:10:12saya akan mengatakan,
00:10:14tentu saja,
00:10:15tim manajemen saya ada di ruangan ini,
00:10:17jadi kita tidak perlu membicarakan itu.
00:10:20Tapi sebenarnya,
00:10:21saya menduga banyak dari Anda langsung melompat ke kesimpulan yang jauh lebih jelas.
00:10:24Ini sangat mirip dengan 'signals'.
00:10:28Dan ya,
00:10:29saya sedang menjelaskan sistem yang terdengar seperti 'signals'.
00:10:31Ini adalah cara untuk menyusun komputasi,
00:10:34melacak dependensi,
00:10:35dengan sejumlah memoization otomatis.
00:10:37Dan saya harus mencatat bahwa kami mengambil inspirasi dari berbagai sistem,
00:10:42terutama kompilator Rust dan sistem yang disebut Salsa.
00:10:45Dan bahkan ada literatur akademis tentang konsep-konsep ini yang disebut Adaptons,
00:10:50jika Anda tertarik.
00:10:51Oke,
00:10:51jadi mari kita lihat apa,
00:10:53mari kita lihat seperti apa ini dalam praktiknya,
00:10:55dan kemudian kita akan membuat lompatan yang sangat mengejutkan dari contoh kode di JavaScript ke Rust.
00:11:01Jadi, inilah contoh infrastruktur yang kami bangun.
00:11:05Fungsi TurboTask adalah unit kerja yang di-cache dalam kompilator kami.
00:11:12Jadi,
00:11:13setelah Anda menganotasi fungsi seperti ini,
00:11:15kami bisa melacaknya,
00:11:17kami bisa membuat kunci cache dari parameternya,
00:11:20dan itu memungkinkan kami untuk menyimpannya di cache dan menjalankannya kembali saat kami membutuhkannya.
00:11:28Tipe VC di sini,
00:11:29Anda bisa menganggapnya seperti 'signals',
00:11:32ini adalah nilai reaktif,
00:11:33VC adalah singkatan dari 'value cell',
00:11:35tapi 'signal' mungkin nama yang sedikit lebih baik.
00:11:39Ketika Anda mendeklarasikan parameter seperti ini,
00:11:42Anda mengatakan ini mungkin berubah,
00:11:44saya ingin menjalankannya kembali saat berubah.
00:11:47Jadi bagaimana kita tahu itu?
00:11:49Jadi kami membaca nilai-nilai ini melalui 'await'.
00:11:52Setelah Anda 'await' nilai reaktif seperti ini,
00:11:55kami secara otomatis melacak dependensinya.
00:11:58Dan kemudian akhirnya,
00:11:59tentu saja,
00:12:00kami melakukan komputasi sebenarnya yang ingin kami lakukan,
00:12:04dan kami menyimpannya dalam sebuah 'cell'.
00:12:07Jadi karena kami telah secara otomatis melacak dependensi,
00:12:11kami tahu bahwa fungsi ini bergantung pada isi file dan nilai konfigurasi.
00:12:17Dan setiap kali kami menyimpan hasil baru ke dalam 'cell',
00:12:20kami bisa membandingkannya dengan yang sebelumnya,
00:12:23dan kemudian jika ada perubahan,
00:12:24kami bisa menyebarkan notifikasi kepada semua orang yang telah membaca nilai itu.
00:12:29Jadi konsep perubahan ini adalah kunci pendekatan kami terhadap inkrementalitas.
00:12:33Dan ya, sekali lagi, kasus paling sederhana ada di sini.
00:12:37Jika file berubah,
00:12:38Turbo Pack akan mengamati itu,
00:12:40membatalkan eksekusi fungsi ini,
00:12:42dan menjalankannya kembali segera.
00:12:45Dan kemudian jika kami kebetulan menghasilkan AST yang sama,
00:12:48kami akan berhenti di situ karena kami menghitung 'cell' yang sama.
00:12:53Sekarang,
00:12:54untuk mengurai file,
00:12:55hampir tidak ada editan yang bisa Anda buat yang tidak benar-benar mengubah AST.
00:13:00Tapi kita bisa memanfaatkan kemampuan komposisi fundamental dari fungsi Turbo Pack untuk membawa ini lebih jauh.
00:13:07Jadi di sini,
00:13:09kita melihat fungsi cache Turbo Pack lain yang mengekstrak impor dari sebuah modul.
00:13:15Anda bisa membayangkan ini adalah tugas yang sangat umum yang kami miliki di Bundler.
00:13:20Kita perlu mengekstrak impor hanya untuk benar-benar menemukan semua modul di aplikasi Anda.
00:13:25Kami memanfaatkannya untuk memilih cara terbaik mengelompokkan modul menjadi 'chunks'.
00:13:29Dan tentu saja,
00:13:30grafik impor penting untuk tugas-tugas dasar seperti 'tree shaking'.
00:13:34Dan karena ada begitu banyak konsumen data impor yang berbeda,
00:13:39cache sangat masuk akal.
00:13:41Jadi implementasi ini tidak terlalu istimewa.
00:13:44Ini seperti apa yang akan Anda temukan di bundler jenis apa pun.
00:13:46Kami menelusuri AST,
00:13:47mengumpulkan impor ke dalam beberapa struktur data khusus yang kami suka,
00:13:52dan kemudian kami mengembalikannya.
00:13:55Tapi ide kuncinya di sini adalah kami menyimpannya ke dalam 'cell' lain.
00:13:58Jadi jika modul berubah,
00:14:00kita memang perlu menjalankan ulang fungsi ini karena kita membacanya.
00:14:05Tapi jika Anda memikirkan jenis perubahan yang Anda buat pada modul,
00:14:08sangat sedikit di antaranya yang benar-benar memengaruhi impor.
00:14:12Jadi Anda mengubah modul,
00:14:14Anda memperbarui isi fungsi,
00:14:16literal string,
00:14:18detail implementasi apa pun.
00:14:20Itu akan membatalkan fungsi ini dan kemudian kami akan menghitung kumpulan impor yang sama.
00:14:25Dan kemudian kami tidak membatalkan apa pun yang telah membaca ini.
00:14:29Jadi jika Anda memikirkannya dalam sesi HMR,
00:14:32ini berarti kita memang perlu mengurai ulang file Anda,
00:14:35tapi kita tidak perlu lagi memikirkan bagaimana membuat keputusan 'chunking'.
00:14:40Kita tidak perlu memikirkan hasil 'tree shaking' apa pun karena kita tahu itu tidak berubah.
00:14:45Jadi kita bisa langsung melompat dari mengurai file,
00:14:48melakukan analisis sederhana ini,
00:14:50dan kemudian langsung melompat ke menghasilkan keluaran.
00:14:53Dan ini adalah salah satu cara kami memiliki waktu refresh yang sangat cepat.
00:14:57Jadi ini cukup imperatif.
00:15:02Cara lain untuk memikirkan ide dasar ini adalah sebagai grafik node.
00:15:06Jadi di sini di sebelah kiri,
00:15:08Anda mungkin membayangkan 'cold build'.
00:15:12Awalnya,
00:15:12kita memang harus membaca setiap file,
00:15:14mengurai semuanya,
00:15:15menganalisis semua impor.
00:15:17Dan sebagai efek samping dari itu,
00:15:18kami telah mengumpulkan semua informasi dependensi dari aplikasi Anda.
00:15:21Dan kemudian ketika ada yang berubah,
00:15:23kita bisa memanfaatkan grafik dependensi yang telah kita bangun untuk menyebarkan invalidasi,
00:15:29kembali ke 'stack',
00:15:30dan menjalankan kembali fungsi Turbo Pack.
00:15:32Dan jadi jika mereka menghasilkan nilai baru,
00:15:34kami berhenti di situ.
00:15:35Jika tidak, kami terus menyebarkan invalidasi.
00:15:37Jadi bagus.
00:15:41Anda tahu,
00:15:41ini sebenarnya semacam penyederhanaan besar-besaran dari apa yang kami lakukan dalam praktik,
00:15:46Anda mungkin membayangkan.
00:15:47Jadi di Turbo Pack hari ini,
00:15:49ada sekitar 2.500 fungsi Turbo task yang berbeda.
00:15:53Dan dalam build yang khas,
00:15:55kita mungkin memiliki jutaan tugas yang berbeda.
00:15:58Jadi ini benar-benar terlihat mungkin sedikit lebih seperti ini.
00:16:01Sekarang,
00:16:02saya tidak benar-benar berharap Anda bisa membaca ini.
00:16:04Tidak bisa benar-benar muat di slide.
00:16:06Jadi mungkin kita harus memperkecil tampilan.
00:16:08Oke, jadi itu jelas tidak membantu.
00:16:14Pada kenyataannya,
00:16:15kami memang memiliki cara yang lebih baik untuk melacak dan memvisualisasikan apa yang terjadi di dalam Turbo Pack.
00:16:21Tapi pada dasarnya,
00:16:22itu berfungsi dengan membuang sebagian besar informasi dependensi.
00:16:26Dan sekarang saya menduga beberapa dari Anda mungkin sebenarnya memiliki pengalaman bekerja dengan 'signals',
00:16:33mungkin pengalaman buruk.
00:16:34Anda tahu,
00:16:35saya pribadi sebenarnya suka 'stack trace' dan bisa masuk dan keluar dari fungsi dalam debugger.
00:16:41Jadi mungkin Anda curiga bahwa ini adalah obat mujarab yang lengkap.
00:16:45Jelas ini datang dengan 'trade-off'.
00:16:47Dan ya,
00:16:48jadi untuk itu saya tentu akan mengatakan,
00:16:51yah,
00:16:52Anda tahu,
00:16:53yang sebenarnya akan saya katakan adalah semua rekayasa perangkat lunak adalah tentang mengelola 'trade-off'.
00:17:01Kami tidak selalu menyelesaikan masalah secara persis,
00:17:04tapi kami benar-benar memilih serangkaian 'trade-off' baru untuk memberikan nilai.
00:17:08Jadi untuk mencapai tujuan desain kami seputar 'incremental build' di Turbo Pack,
00:17:13kami mencurahkan semua upaya kami pada model pemrograman reaktif inkremental ini.
00:17:19Dan ini tentu saja memiliki beberapa konsekuensi yang sangat alami.
00:17:23Jadi,
00:17:24Anda tahu,
00:17:25mungkin kami sebenarnya benar-benar memecahkan masalah sistem caching buatan tangan dan logika invalidasi yang rumit.
00:17:33Sebagai gantinya,
00:17:35kami harus mengelola beberapa infrastruktur caching yang rumit.
00:17:39Dan tentu saja,
00:17:39Anda tahu,
00:17:40itu terdengar seperti 'trade-off' yang sangat bagus bagi saya.
00:17:42Saya suka infrastruktur caching yang rumit,
00:17:44tapi kita semua harus hidup dengan konsekuensinya.
00:17:48Jadi yang pertama tentu saja adalah overhead inti dari sistem ini.
00:17:54Anda tahu,
00:17:55jadi jika Anda memikirkannya dalam sesi build atau HMR tertentu,
00:18:00Anda tidak benar-benar mengubah banyak hal.
00:18:04Jadi kami melacak semua informasi dependensi antara setiap impor dan setiap hasil resolusi di aplikasi Anda,
00:18:10tapi Anda hanya akan benar-benar mengubah beberapa di antaranya.
00:18:13Jadi sebagian besar informasi dependensi yang kami kumpulkan sebenarnya tidak pernah dibutuhkan.
00:18:16Jadi,
00:18:17Anda tahu,
00:18:18untuk mengelola ini,
00:18:19kami harus sangat fokus pada mendorong,
00:18:21pada peningkatan performa lapisan caching ini untuk menurunkan overhead dan membiarkan sistem kami berskala ke aplikasi yang lebih besar dan lebih besar.
00:18:30Dan yang berikutnya dan paling jelas hanyalah memori.
00:18:34Anda tahu,
00:18:35cache selalu secara fundamental merupakan 'trade-off' waktu versus memori.
00:18:38Dan milik kami tidak benar-benar melakukan sesuatu yang berbeda di sana.
00:18:41Tujuan sederhana kami adalah ukuran cache harus berskala linier dengan ukuran aplikasi Anda.
00:18:49Tapi sekali lagi, kita harus berhati-hati tentang overhead.
00:18:51Yang berikutnya ini sedikit halus.
00:18:54Jadi kami memiliki banyak algoritma di bundler seperti yang Anda duga.
00:18:58Dan beberapa di antaranya semacam memerlukan pemahaman sesuatu yang global tentang aplikasi Anda.
00:19:03Nah,
00:19:03itu masalah karena kapan pun Anda bergantung pada informasi global,
00:19:07itu berarti setiap perubahan mungkin membatalkan operasi itu.
00:19:10Jadi kita harus berhati-hati tentang bagaimana kita merancang algoritma ini,
00:19:14menyusun hal-hal dengan hati-hati agar kita bisa mempertahankan inkrementalitas.
00:19:17Dan akhirnya, yang satu ini mungkin sedikit keluhan pribadi.
00:19:24Semuanya asinkron di Turbo Pack.
00:19:27Dan jadi ini bagus untuk skalabilitas horizontal,
00:19:29tapi sekali lagi,
00:19:29itu merugikan tujuan fundamental kami,
00:19:31seperti,
00:19:32Anda tahu,
00:19:32tujuan profil performa debugging.
00:19:38Jadi saya yakin banyak dari Anda memiliki pengalaman debugging asinkron di alat pengembang Chrome.
00:19:46Dan ini umumnya pengalaman yang cukup menyenangkan.
00:19:48Tidak selalu ideal.
00:19:49Dan saya jamin Rust dengan LLDB jauh tertinggal.
00:19:53Jadi untuk mengelola itu,
00:19:55kami harus berinvestasi dalam alat visualisasi,
00:19:58instrumentasi,
00:19:59dan pelacakan kustom.
00:20:01Dan lihat itu,
00:20:02seperti proyek infrastruktur lain yang bukan bundler.
00:20:07Oke,
00:20:07jadi mari kita lihat dan periksa apakah kita membuat taruhan yang tepat.
00:20:11Jadi di Vercel,
00:20:12kami memiliki aplikasi produksi yang sangat besar.
00:20:17Kami pikir ini mungkin salah satu yang terbesar di dunia,
00:20:19tapi Anda tahu,
00:20:19kami tidak benar-benar tahu.
00:20:21Tapi itu memang memiliki sekitar 80.000 modul di dalamnya.
00:20:23Jadi mari kita lihat bagaimana performa Turbo Pack di sana.
00:20:26Untuk 'fast refresh',
00:20:28kami benar-benar mendominasi apa yang mampu diberikan Web Pack.
00:20:32Tapi ini semacam berita lama.
00:20:33Turbo Pack untuk pengembangan sudah ada sejak beberapa waktu,
00:20:36dan saya sangat berharap semua orang setidaknya menggunakannya dalam pengembangan.
00:20:39Tapi Anda tahu,
00:20:39hal baru di sini hari ini,
00:20:40tentu saja,
00:20:41adalah bahwa build sudah stabil.
00:20:42Jadi mari kita lihat sebuah build.
00:20:44Dan di sini Anda bisa melihat kemenangan substansial atas Web Pack untuk aplikasi ini.
00:20:49Build khusus ini sebenarnya berjalan dengan lapisan caching sistem file eksperimental baru kami.
00:20:53Jadi sekitar 16 dari 94 detik itu hanyalah membersihkan cache di akhir.
00:20:59Dan ini adalah sesuatu yang akan kami kerjakan untuk ditingkatkan seiring dengan stabilnya caching sistem file.
00:21:04Tapi tentu saja,
00:21:04hal tentang 'cold build' adalah mereka 'dingin',
00:21:06tidak ada yang inkremental.
00:21:07Jadi mari kita lihat 'warm build' yang sebenarnya.
00:21:10Jadi menggunakan cache dari 'cold build',
00:21:13kita bisa melihat ini.
00:21:14Jadi ini hanyalah intipan di mana kita berada hari ini.
00:21:17Karena kami memiliki sistem caching yang sangat terperinci ini,
00:21:19kami sebenarnya bisa langsung menulis cache ke disk,
00:21:22dan kemudian pada build berikutnya,
00:21:23membacanya kembali,
00:21:24mencari tahu apa yang berubah,
00:21:25dan menyelesaikan build.
00:21:26Oke,
00:21:27jadi ini terlihat cukup bagus,
00:21:28tapi banyak dari Anda mungkin berpikir,
00:21:30yah,
00:21:31mungkin saya pribadi tidak memiliki aplikasi Next.js terbesar di dunia.
00:21:34Jadi mari kita lihat contoh yang lebih kecil.
00:21:37Situs web react.dev sedikit lebih kecil.
00:21:41Ini juga agak menarik karena ini adalah kompilator React.
00:21:44Tidak mengherankan,
00:21:45ini adalah pengadopsi awal kompilator React.
00:21:47Dan kompilator React diimplementasikan di Babel.
00:21:49Dan ini semacam masalah untuk pendekatan kami karena itu berarti untuk setiap file di aplikasi,
00:21:53kita perlu meminta Babel untuk memprosesnya.
00:21:55Jadi,
00:21:55dan secara fundamental,
00:21:57saya akan mengatakan kami,
00:21:58atau saya,
00:21:58saya tidak bisa membuat kompilator React lebih cepat.
00:22:01Itu bukan pekerjaan saya.
00:22:02Pekerjaan saya adalah Turbo Pack.
00:22:03Tapi kita bisa mencari tahu kapan tepatnya memanggilnya.
00:22:07Jadi melihat waktu 'fast refresh',
00:22:10saya sebenarnya sedikit kecewa dengan hasil ini.
00:22:13Dan ternyata sekitar 130 dari 140 milidetik itu adalah kompilator React.
00:22:18Dan baik Turbo Pack maupun Web Pack melakukan itu.
00:22:22Tapi dengan Turbo Pack,
00:22:23kami bisa,
00:22:24setelah kompilator React memproses perubahan ini,
00:22:26kami bisa melihat,
00:22:27oh,
00:22:28impor tidak berubah.
00:22:29Masukkan ke keluaran dan teruskan.
00:22:31Sekali lagi,
00:22:32pada 'cold build',
00:22:33kami melihat semacam kemenangan 3x yang konsisten ini.
00:22:37Dan hanya untuk memperjelas, ini di mesin saya.
00:22:39Tapi sekali lagi,
00:22:41tidak ada inkrementalitas dalam 'cold build'.
00:22:44Dan dalam 'warm build',
00:22:45kami melihat waktu yang jauh lebih baik ini.
00:22:47Jadi sekali lagi,
00:22:48dengan 'warm build',
00:22:49kami sudah memiliki cache di disk.
00:22:52Yang perlu kami lakukan pada dasarnya,
00:22:53setelah kami mulai,
00:22:54adalah mencari tahu file mana di aplikasi yang berubah,
00:22:56menjalankan kembali pekerjaan-pekerjaan itu,
00:22:58dan kemudian menggunakan kembali semua hal lain dari build sebelumnya.
00:23:01Jadi pertanyaan dasarnya adalah, apakah kita sudah Turbo?
00:23:05Ya.
00:23:06Jadi ya, ini dibahas dalam pidato utama, tentu saja.
00:23:09Turbo Pack stabil mulai dari Next 16.
00:23:12Dan kami bahkan adalah bundler default untuk Next.
00:23:14Jadi, Anda tahu, misi berhasil, sama-sama.
00:23:17Tapi. (tertawa) (penonton bertepuk tangan)
00:23:23Dan jika Anda memperhatikan hal 'revert' di pidato utama,
00:23:26itu adalah saya yang mencoba menjadikan Turbo Pack sebagai default.
00:23:30Hanya butuh tiga kali percobaan.
00:23:31Tapi yang benar-benar ingin saya sampaikan kepada Anda,
00:23:34sekali lagi,
00:23:35adalah ini.
00:23:35Anda tahu, karena kami belum selesai.
00:23:37Kami masih punya banyak pekerjaan yang harus dilakukan pada performa,
00:23:40dan menyempurnakan lapisan caching sistem file.
00:23:42Saya sarankan Anda semua mencobanya dalam pengembangan.
00:23:44Dan itu saja.
00:23:46Terima kasih banyak.
00:23:47Silakan temui saya, ajukan pertanyaan.
00:23:49(penonton bertepuk tangan) (musik ceria) (musik ceria)

Key Takeaway

Turbo Pack dari Vercel merevolusi performa bundling dengan sistem reaktif inkremental berbasis 'signals' yang secara otomatis mengelola caching dan dependensi, menghasilkan waktu build dan refresh yang jauh lebih cepat serta lebih efisien.

Highlights

Turbo Pack menggunakan model pemrograman reaktif inkremental yang terinspirasi oleh 'signals' untuk mencapai performa bundling yang sangat cepat.

Tujuan utama Turbo Pack adalah membuat setiap operasi bundler dapat di-cache, sehingga biaya build sebanding dengan ukuran perubahan kode, bukan ukuran keseluruhan aplikasi.

Sistem TurboTask dan Value Cells (VC) secara otomatis melacak dependensi dan membatalkan hanya bagian yang relevan dari build saat ada perubahan, menghentikan propagasi jika hasilnya tidak berubah.

Pendekatan ini mengatasi masalah caching manual dan logika invalidasi yang rumit yang sering ditemukan pada bundler tradisional.

Turbo Pack menunjukkan peningkatan performa yang signifikan dibandingkan Webpack untuk 'fast refresh', 'cold build', dan 'warm build' pada aplikasi besar maupun kecil.

Meskipun ada tantangan seperti overhead sistem, manajemen memori, algoritma global, dan debugging asinkron, Vercel berinvestasi pada alat kustom untuk mengelolanya.

Turbo Pack telah stabil dan menjadi bundler default untuk Next.js 16, dengan pekerjaan berkelanjutan untuk menyempurnakan performa dan lapisan caching sistem file.

Timeline

Pengantar dan Latar Belakang Pembicara

Luke Sandberg, seorang insinyur perangkat lunak di Vercel yang mengerjakan Turbo Pack, memperkenalkan dirinya. Ia berbagi pengalamannya sebelumnya di Google dengan alat web internal dan kompilator, yang memberinya perspektif unik saat bergabung dengan Vercel. Bagian ini menetapkan kredibilitas pembicara dan memperkenalkan topik utama: pilihan desain di Turbo Pack yang bertujuan untuk performa fantastis. Ini memberikan landasan mengapa Turbo Pack dikembangkan dan apa yang ingin dicapai.

Tujuan Desain Utama: Build Inkremental

Pembicara menjelaskan bahwa tujuan desain utama Turbo Pack adalah menghindari 'cold build' dan berfokus pada inkrementalitas melalui caching. Ide utamanya adalah membuat setiap operasi bundler dapat di-cache, sehingga hanya pekerjaan yang terkait dengan perubahan yang perlu diulang. Dengan memastikan biaya build sebanding dengan ukuran perubahan, bukan ukuran aplikasi, Turbo Pack bertujuan untuk memberikan performa yang konsisten dan cepat bagi pengembang, tidak peduli seberapa kompleks aplikasi mereka.

Tantangan Caching Naif dan Bundler Reaktif

Luke memulai dengan contoh bundler 'bayi' yang naif, menunjukkan bagaimana ia mengurai file berkali-kali dan tidak inkremental. Ia kemudian mencoba menambahkan cache sederhana, tetapi segera menghadapi masalah seperti perubahan file, symlink, konfigurasi yang kompleks, dan mutasi AST. Upaya untuk membuat bundler reaktif dengan callback juga gagal karena masih memerlukan pengulangan seluruh proses build dan sulit dipelihara, menyoroti kompleksitas masalah yang coba dipecahkan oleh Turbo Pack.

Persyaratan Sistem Inkremental yang Ideal

Setelah menunjukkan kegagalan pendekatan naif, pembicara menguraikan apa yang sebenarnya mereka inginkan dari sistem. Ini termasuk kemampuan untuk menyimpan cache setiap operasi mahal dengan mudah, otomatisasi pelacakan dependensi dan kunci cache yang benar, penanganan input yang berubah (file, konfigurasi, variabel lingkungan), reaktivitas tanpa callback manual, dan pemanfaatan arsitektur multi-threaded modern. Persyaratan ini sangat mirip dengan konsep 'signals' dalam pemrograman reaktif.

Solusi Turbo Pack: Pemrograman Reaktif dengan TurboTask

Luke menjelaskan bahwa solusi mereka terinspirasi oleh 'signals' dan sistem seperti Salsa, menggunakan konsep 'TurboTask' sebagai unit kerja yang dapat di-cache. 'Value Cell' (VC) adalah nilai reaktif yang secara otomatis melacak dependensi saat di-'await'. Ini memungkinkan Turbo Pack untuk membatalkan dan menjalankan kembali hanya fungsi yang relevan saat input berubah, dan menghentikan propagasi jika hasilnya tidak berubah, seperti dalam kasus `extract_imports` di mana perubahan kode tidak selalu mengubah impor, yang menjelaskan waktu refresh yang cepat. Turbo Pack memiliki sekitar 2.500 fungsi TurboTask yang berbeda dan jutaan tugas dalam build tipikal.

Pertimbangan dan Tantangan Model Reaktif

Pembicara mengakui bahwa sistem ini bukan obat mujarab dan memiliki konsekuensi, karena 'semua rekayasa perangkat lunak adalah tentang mengelola trade-off'. Tantangan meliputi overhead inti dari melacak jutaan dependensi, kebutuhan memori untuk cache, kesulitan dalam merancang algoritma global agar tetap inkremental, dan kompleksitas debugging lingkungan asinkron di Rust. Untuk mengatasi ini, Vercel berinvestasi dalam alat visualisasi, instrumentasi, dan pelacakan kustom, menunjukkan pekerjaan rekayasa berkelanjutan yang diperlukan.

Hasil Performa dan Studi Kasus

Luke menyajikan data performa nyata yang menunjukkan bahwa Turbo Pack secara signifikan mengungguli Webpack. Pada aplikasi produksi Vercel yang besar (80.000 modul), Turbo Pack mendominasi 'fast refresh' dan menunjukkan kemenangan substansial pada 'cold build' (94 detik vs. 300+ detik Webpack) dan 'warm build' (2.5 detik). Bahkan pada situs react.dev yang lebih kecil, Turbo Pack menunjukkan kemenangan 3x pada 'cold build' dan waktu 'warm build' yang jauh lebih baik, meskipun ada overhead dari kompilator React, memvalidasi klaim performa Turbo Pack dengan bukti konkret.

Kesimpulan dan Ajakan

Pembicara mengonfirmasi bahwa Turbo Pack stabil sejak Next.js 16 dan telah menjadi bundler default. Meskipun demikian, masih ada banyak pekerjaan yang harus dilakukan untuk meningkatkan performa dan menyempurnakan lapisan caching sistem file. Ia mendorong semua pengembang untuk mencoba Turbo Pack dalam pengembangan mereka, merangkum keberhasilan Turbo Pack dan melihat ke masa depan, sekaligus mengakui bahwa pengembangan berkelanjutan masih berlangsung.

Community Posts

View all posts