Modul ES6 di browser: apakah siap atau tidak?

Pernahkah Anda mendengar tentang penggunaan modul ES6 di browser? Sebenarnya, ini adalah modul ES6 biasa. Mereka hanya berlaku dalam kode yang ditujukan untuk browser.



Jika ada yang tidak tahu - ini adalah tampilannya.

Ada satu halaman index.html:

<!DOCTYPE html>
<html>
  <body>
    <div id="app"></div>
  
    <script type="module" src="index.mjs"></script>
    <!--     "module" -->
  </body>
</html>

Ada file yang index.mjsmewakili modul yang terhubung ke halaman:

import { doSomething } from './utils.mjs';

doSomething('Make me a sandwich');

Modul ini, pada gilirannya, mengimpor fungsi doSomethingdari modul utils.mjs:

export const doSomething = message => {
  console.log('No.');
};

Modul ES6 telah ada selama bertahun-tahun. Dan mungkin Anda berpikir untuk mencobanya. Saya menggunakannya selama sekitar satu bulan di proyek saya sendiri. Pada saat yang sama, saya sampai pada kesimpulan bahwa ...

Penangguhan!

Tentang dukungan browser untuk modul


Sebelum saya berbicara tentang apa yang saya pahami, saya sarankan untuk melihat dukungan browser untuk modul. Saya menulis materi ini di awal tahun 2020, sehingga tingkat dukungan untuk modul cukup mengesankan 90%.


Dukungan untuk modul dengan browser menurut caniuse.com,

saya cukup senang dengan 90% ini (saya tidak memperhitungkan kebutuhan 10% pengguna), walaupun Anda mungkin ingin lebih bertanggung jawab. Tetapi, bahkan mempertimbangkan hal ini, jika proyek Anda tidak dirancang untuk IE, atau UC, atau Opera Mini, tingkat dukungan ini berarti bahwa hampir 100% audiens target Anda akan dapat bekerja dengan proyek Anda tanpa masalah.

Benar, dukungan browser untuk modul hanyalah permulaan. Di sini saya ingin menemukan jawaban untuk tiga pertanyaan yang muncul pada awal perjalanan saya menuju modul:

  • Apakah penggunaan modul di browser memiliki keunggulan?
  • Bagaimana dengan kontra?
  • Saya yakin saya memiliki pertanyaan ketiga, tetapi sekarang saya tidak dapat mengingatnya.

Mari kita cari tahu ...

Apa kelebihan menggunakan modul di browser?


Ini adalah JavaScript murni! Tidak ada pipa proyek perakitan, tidak ada file konfigurasi Webpack 400-baris, tidak ada Babel, tidak ada plugins dan preset, dan tidak ada modul tambahan 45 npm. Hanya Anda dan kode Anda.

Ada sesuatu yang menyegarkan tentang penulisan kode yang akan dieksekusi di browser persis dalam bentuk di mana kode itu dibuat. Ini mungkin memerlukan sedikit usaha, tetapi hasilnya sangat menyenangkan. Ini adalah cara mengendarai mobil dengan transmisi manual.

Begitu. Kelebihan modul ES6 adalah JavaScript murni, ini adalah kurangnya perakitan, konfigurasi proyek, ini adalah penolakan terhadap dependensi yang telah menjadi tidak perlu. Apa lagi? Apakah ada hal lain?

Tidak, tidak lebih.

Apa kerugian menggunakan modul di browser?


▍ Perbandingan modul dan bundler


Ketika berpikir apakah akan menggunakan modul ES6 di browser, Anda sebenarnya harus memilih antara menggunakan modul dan bundler seperti Webpack, Parcel, atau Rollup.

Anda dapat (mungkin) menggunakan keduanya, tetapi pada kenyataannya, jika Anda berencana untuk menjalankan kode melalui bundler, tidak ada alasan untuk menggunakan desain <script type="module">untuk memuat file bundel.

Jadi, berdasarkan asumsi bahwa seseorang sedang mempertimbangkan kemungkinan menggunakan modul ES6 alih-alih bundler, inilah yang harus ia hilangkan:

  • Minifikasi kode yang sudah jadi.
  • Fitur JavaScript mutakhir.
  • Sintaks yang berbeda dari sintaks JavaScript (Bereaksi, TypeScript, dll.).
  • Modul NPM.
  • Caching

Pertimbangkan tiga paragraf pertama dari daftar ini secara lebih rinci.

▍ Ukuran File


Ukuran proyek saya, yang menggunakan modul, adalah 34 Kb. Karena saya tidak menggunakan langkah build proyek, kode yang dikirimkan melalui jaringan berisi nama variabel yang sangat panjang, ada banyak sekali komentar di dalamnya. Selain itu, ini mewakili sejumlah besar file kecil, yang tidak terlalu baik dalam hal kompresi data.

Jika saya memasukkan semua ini ke dalam bundel menggunakan Parcel , maka ukuran apa yang akan berubah menjadi 18 Kb. Kalkulator Santai Casio saya melaporkan bahwa ini adalah "sekitar setengah" kode proyek di mana bundler tidak digunakan. Ini sebagian karena fakta bahwa Parcel meminimalkan file, tetapi juga karena bahan dengan pendekatan ini lebih baik dikompresi menggunakan gzip.

Kompresi data menarik perhatian kita ke masalah lain: cara mengatur file (dalam arti kenyamanan pengembangan) langsung ditransfer ke cara file ditransfer melalui jaringan. Dan cara file diatur selama pengembangan tidak selalu sesuai dengan bagaimana Anda ingin melihatnya di situs. Misalnya, 150 modul (file) mungkin masuk akal saat mengerjakan proyek. Dan materi yang sama yang ditransfer ke browser dapat dibenarkan untuk diatur dalam 12 bundel.

Saya akan menjelaskan ide ini. Saya tidak berbicara tentang fakta bahwa menggunakan modul berarti bahwa file tidak dapat dibundel dan diperkecil (fakta bahwa ini tidak dapat dilakukan adalah ilusi). Maksud saya, tidak masuk akal untuk melakukan keduanya.

Ya, ini pengamatan yang lucu. Dalam aplikasi saya, sampai saya menulis bagian ini, modul digunakan (saya tekankan!). Saya memasang Parcel untuk menghitung ukuran perakitan yang benar. Dan sekarang saya tidak melihat alasan untuk kembali ke modul normal. Nah, apakah itu tidak menarik!

▍Hidup tanpa transpilasi


Selama bertahun-tahun, saya sangat terbiasa menggunakan konstruksi sintaksis JavaScript terbaru, dan alat Babel yang luar biasa, yang mengubahnya menjadi kode yang dipahami semua browser. Saya sangat terbiasa sehingga saya jarang berpikir tentang dukungan browser (tentu saja, dengan pengecualian DOM dan CSS).

Ketika saya pertama kali mencoba type=«module», saya akan melakukan semuanya sendiri. Tujuan saya adalah browser baru, jadi saya pikir saya bisa menggunakan JavaScript modern, yang sudah biasa saya gunakan.

Tetapi kenyataannya tidak begitu cerah. Cobalah untuk menjawab pertanyaan-pertanyaan berikut dengan cepat dan tanpa melihat ke mana-mana. Apakah Edge MendukungflatMap()? Apakah Safari mendukung penugasan destruktif (objek dan array)? Apakah Chrome mendukung koma setelah argumen fungsi terakhir? Apakah Firefox mendukung eksponensial?

Sebagai contoh, saya harus mencari jawaban untuk pertanyaan-pertanyaan ini, melakukan tes lintas browser. Tapi saya menggunakan semua ini selama berabad-abad. Dalam setiap aplikasi yang cukup besar, ini kemungkinan besar akan menyebabkan kesalahan produksi.

Ini juga berarti bahwa saya tidak akan dapat menggunakan inovasi JavaScript yang paling luar biasa sejak munculnya metode array slice()- yang disebut operator urutan opsional . Saya menggunakan desain ajaib sepertiprop?.valuehanya sekitar satu bulan (sejak saat itu alat Create React App mulai mendukung mereka tanpa pengaturan tambahan). Tetapi sudah tidak nyaman bagi saya untuk bekerja tanpa mereka.

▍ Beban caching


Caching bagi saya adalah batu sandungan terbesar. Faktanya, fakta bahwa solusi untuk masalah caching ternyata cukup menarik ternyata menjadi alasan utama mengapa saya memutuskan untuk menulis materi ini.

Seperti yang Anda yakin, Anda tahu, ketika bahan diproses menggunakan bundler, masing-masing file yang dihasilkan mendapat nama unik - semacam index.38fd9e.js. Isi file dengan nama ini tidak pernah (tidak pernah) berubah. Oleh karena itu, dapat di-cache oleh browser untuk periode yang tidak terbatas. Jika file seperti itu diunduh satu kali, Anda tidak perlu mengunduhnya lagi.

Ini adalah sistem yang luar biasa - kecuali Anda mencoba menemukan jawaban untuk pertanyaan bagaimana menghapus cache.

Modul dimuat menggunakan desain seperti<script type="module" src="index.mjs"></script>. Hash dalam nama file tidak digunakan. Bagaimana, dalam situasi ini, ia seharusnya memberi tahu browser tentang tempat untuk mengunduhnya index.mjs- dari cache atau dari jaringan?

Perlu dicatat bahwa hampir memungkinkan untuk membuat cache berfungsi, tetapi itu akan membutuhkan usaha. Inilah yang Anda butuhkan untuk ini:

  • Anda harus mengatur judul semua jawaban cache-controlke suatu nilai no-cache. Hebatnya, tanpa-cache tidak berarti "jangan cache." Ini berarti bahwa file tersebut harus di-cache, tetapi file tersebut tidak boleh "digunakan untuk memenuhi permintaan berikutnya tanpa verifikasi yang berhasil pada server sumber."
  • ETag. — () , , , . , 38fd9e .
  • CDN- , . ETag . . CDN- . ( ETag) . (, , Firebase).
  • -, , « » . , , , , .

Akibatnya, ketika pengunjung mengunjungi kembali situs tersebut, browser akan mengatakan: “Saya perlu mengunduh file index.mjs. Saya melihat file ini sudah ada di cache saya, ETag-nya 38fd9e. Saya akan meminta file ini dari server, tetapi saya akan memberitahunya untuk mengirimkannya kepada saya hanya jika ETagnya tidak 38fd9e. " Pekerja layanan akan mencegat permintaan ini, mengabaikan ETag dan mengembalikannya index.mjsdari cache (file ini masuk ke cache ketika halaman dimuat terakhir kali). Kemudian pekerja layanan akan mengarahkan permintaan ke server. Server akan mengembalikan pesan yang menyatakan bahwa file tidak berubah, atau file yang akan disimpan dalam cache.

Menurut saya, semua ini sangat merepotkan.

Sekarang, jika Anda tertarik, kode pekerja layanan:

self.addEventListener('fetch', e => {
  e.respondWith(
    (async () => {
      //       
      const cacheResponse = await caches.match(e.request);
      
      //   (),   
      // (ETag-    )
      fetch(e.request).then(fetchResponse => {
        caches
          .open(CACHE_NAME)
          .then(cache => cache.put(e.request, fetchResponse));
      });
      
      if (cacheResponse) return cacheResponse;
      
      return fetch(e.request);
    })()
  );
});

Saya malas, jadi saya tidak belajar dan tidak menggunakan properti FetchEvent.navigationPreload terbaru . Faktanya adalah bahwa pada saat itu saya menghabiskan lebih banyak waktu caching daripada menulis aplikasi (untuk informasi Anda, saya menghabiskan 10 dan 11 jam untuk masalah ini, masing-masing).

Ya, saya ingin mencatat bahwa proposal "kartu impor" ditujukan untuk menyelesaikan beberapa masalah yang dijelaskan di atas. Ini memungkinkan Anda untuk mengatur sesuatu seperti pemetaan index.jsdi index.38fd9e.mjs. Tetapi untuk menghasilkan hash, bagaimanapun, Anda memerlukan semacam pipa perakitan, kartu impor harus tertanam dalam file HTML. Ini artinya diperlukan bundler di sini ... Sebenarnya, dalam situasi ini, modul tidak lagi diperlukan di browser.

Alhasil, meskipun menarik untuk memahami semua ini, itu bisa dibandingkan dengan cara saya mengendarai kemana-mana dengan satu siklus selama satu tahun penuh. Saya tidak akan melakukan ini lagi.

Tapi mungkin tidak semua orang menggunakan bundler?


Saya menulis bahan ini dengan asumsi bahwa semua orang menulis kode dalam modul, menggunakan konstruksi import/exportatau require, dan kemudian mengumpulkan kode ke dalam bundel produksi menggunakan Webpack, Grunt, Gulp atau sesuatu seperti itu.

Apakah ada pengembang yang tidak menggunakan bundler? Adakah orang yang menempatkan kode JavaScript mereka di beberapa file dan mengirimkannya ke produksi tanpa bundling? Mungkin salah satu dari orang-orang ini adalah Anda? Jika demikian, saya ingin tahu semua tentang kehidupan Anda.

Ringkasan


Saya berusaha keras untuk membuat semua keputusan serius, seperti memilih antara modul dan bundler, berdasarkan prinsip utama pengembangan yang efektif. Ini adalah produktivitas dan kualitas.

Sayangnya, penggunaan modul di browser tidak berkontribusi pada satu atau yang lain.

Jika besok saya mulai mengerjakan proyek baru, maka di kepala saya, saya tidak akan memiliki pertanyaan tentang apakah menjalankan aplikasi buat-reaksi lama yang baik. Semua pengaturan awal akan memakan waktu sekitar tiga puluh detik, dan meskipun ukuran proyek awal 40 Kb agak besar, untuk sebagian besar situs ini tidak akan memainkan peran apa pun.

Dan inilah situasi yang berbeda. Misalkan saya perlu mengumpulkan sedikit HTML / CSS dan JavaScript untuk beberapa jenis eksperimen, dan eksperimen semacam itu akan menjadi proyek yang menyertakan lebih banyak file daripada beberapa. Jika, saat mengerjakan proyek ini, saya tidak berencana untuk menghabiskan waktu menyiapkan sistem untuk membangunnya, maka saya mungkin akan menggunakan modul-modul di browser. Dan kemudian - jika saya tidak peduli dengan kinerja proyek ini.

Saya akan tertarik untuk mengetahui bagaimana Webpack dan alat terkait bekerja dengan modul ES6 di browser. Saya percaya bahwa di masa depan, ketika proposal untuk "kartu impor" menerima dukungan yang cukup, bundler mungkin akan menggunakannya sebagai mekanisme untuk abstrak hash yang tidak sedap dipandang yang digunakan saat ini.

Pembaca yang budiman! Sudahkah Anda menggunakan modul ES6 di browser Anda?


All Articles