Setiap pembangun web tahu perasaan apabila melihat aplikasi mereka dipaparkan dengan sempurna dalam persekitaran staging yang terkawal. Melancarkan widget terbenam (embedded widget) memusnahkan keselesaan itu sepenuhnya. Anda bukan lagi arkitek halaman tersebut. Anda adalah tetamu yang tidak diundang, menyuntik aplikasi React ke dalam DOM yang bukan milik anda, kaskad CSS yang tidak anda tulis, dan persekitaran masa larian (runtime environment) yang mungkin bertindak menentang anda. Semasa membina dan melancarkan widget Clanker Support, kami mempelajari bahawa andaian pembangunan web standard akan runtuh sebaik sahaja kod anda berjalan di dalam tema orang lain. Laman hos mungkin menetapkan semula saiz fon, menyembunyikan div kosong, atau menguatkuasakan kitaran hayat skrip yang membatalkan konfigurasi anda sebelum anda sempat membacanya. Berikut adalah peraturan defensif yang kami tulis melalui pengalaman pahit di produksi.
Satu Fail, Satu Mod Kegagalan
Bundler moden menggoda anda dengan pembahagian kod (code splitting) dan import dinamik. Lawanlah godaan itu. Sebuah widget terbenam mesti dilancarkan sebagai satu Immediately Invoked Function Expression (IIFE) fail tunggal. Apabila pelanggan menyalin tag skrip anda ke dalam templat mereka, mereka menjangkakan satu permintaan rangkaian sahaja. Jika bundle anda cuba melakukan lazy-load pada perpustakaan parsing yang berat atau cebisan model bahasa, proses fetch tersebut mungkin gagal secara senyap. Laman hos mungkin mempunyai Dasar Keselamatan Kandungan (Content Security Policy) yang ketat, penyekat iklan yang agresif, atau laluan CDN yang tidak sepadan dengan andaian publicPath anda. Dengan memaksa segalanya ke dalam satu IIFE, anda menghapuskan ketidakpastian daripada pemuatan cebisan (chunk) sekunder. Jika sesuatu dependensi berkeras untuk melakukan lazy-loading pada bahagian dalamannya sendiri, buat alias semasa waktu binaan kepada stub yang ringan. Hasilnya adalah satu artifak, satu mod kegagalan, dan sesi penyahpepijatan yang jauh lebih mudah apabila pengurus laman pelanggan menghantar tangkapan skrin gelembung sembang yang rosak kepada anda.
Shadow DOM Juga Bocor
Pembangun sering menganggap Shadow DOM sebagai kubu yang tidak dapat ditembus. Ia memang mengasingkan selektor anda daripada CSS halaman hos, tetapi ia tidak mengasingkan pewarisan (inheritance). Sifat seperti font-family, line-height, color, dan text-align mengalir ke bawah ke dalam pokok bayangan (shadow tree) anda seolah-olah sempadan itu tidak wujud. Kedai Shopify dengan pengisytiharan global font-family: "Comic Sans MS" akan menjangkiti widget sokongan anda yang direka dengan teliti melainkan anda menetapkan setiap sifat yang boleh diwarisi secara eksplisit pada elemen akar anda. Tetapkan tipografi, jarak, dan penjajaran teks anda sendiri dengan nilai konkrit terus pada peringkat hos. Anggaplah halaman induk itu bermusuhan dan tetapkan semula (reset) semua perkara yang penting bagi anda. Shadow DOM melindungi kelas anda, bukan estetika anda.
Aksi Menghilangkan Div Kosong
Satu perkara ini benar-benar membuatkan kami tergamam. Banyak tema popular, termasuk Shopify Dawn, disertakan dengan peraturan CSS yang kelihatan tidak berbahaya: div:empty { display: none; }. Apabila widget anda dipasang (mount), ia biasanya menyasarkan div hos yang bermula dalam keadaan kosong. Sebelum JavaScript anda dilaksanakan dan React menghidratkan (hydrate) nod tersebut, div itu secara literal adalah kosong. Stylesheet tema menyembunyikannya. Skrip anda berjalan, memanggil ReactDOM.createRoot, dan tiada apa yang muncul. Tiada ralat dalam konsol. Elemen tersebut hanya berhenti wujud dalam susun atur. Penyelesaiannya adalah secara paksa dan eksplisit: gunakan gaya inline display: block !important pada titik pemasangan (mount point) anda. Jangan bergantung kepada perpustakaan CSS-in-JS anda untuk mengendalikan perkara ini kemudian. Menjelang masa stylesheet anda diaplikasikan, tema hos sudah pun menang.
Tinggalkan rem untuk px
Dalam aplikasi biasa, unit relatif seperti rem adalah pilihan yang bertanggungjawab. Dalam widget terbenam, ia adalah satu liabiliti. Nilai rem diselesaikan terhadap saiz fon html akar dokumen hos, bukan widget anda. Jika halaman hos menetapkan html { font-size: 10px; } atau menggunakan helah 62.5% yang lama, keseluruhan skala tipografi dan jarak anda akan beralih tanpa amaran. Ketinggian baris 1.6rem yang selesa mungkin mengecil menjadi 16px, atau padding anda mungkin mengecil menjadi jalur yang tidak dapat dibaca. Oleh kerana anda tidak dapat meramal atau mengawal saiz akar hos, piksel (px) adalah satu-satunya unit yang jujur untuk widget terbenam. Ia dipaparkan pada saiz fizikal yang sama tanpa mengira andaian halaman di sekelilingnya. Tukarkan fleksibiliti kebolehcapaian teori rem dengan kebolehpercayaan praktikal px apabila anda hidup di dalam kaskad laman web lain.
Baca Konfigurasi Anda Sebelum Ia Hilang
Jika anda menghantar konfigurasi ke widget anda melalui atribut data pada tag skrip, anda mesti membacanya secara sinkronus. Pelayar menyediakan document.currentScript supaya skrip boleh memeriksa tagnya sendiri, tetapi rujukan ini adalah sementara. Jika anda menunggu DOMContentLoaded atau sebarang sempadan asinkronus, document.currentScript akan menjadi null. Konfigurasi anda akan lenyap. Baca atribut tersebut dengan segera pada tahap teratas pelaksanaan skrip anda. Dapatkan kunci API, ID widget, dan tema warna pada waktu itu juga, simpan dalam closure atau pemboleh ubah modul, dan hanya selepas itu teruskan dengan memulakan React.
Biarkan URL Skrip Menentukan Asal API
Melakukan hardcoding URL API pengeluaran ke dalam bundle anda adalah kesilapan yang akan berlipat ganda merentasi pelbagai persekitaran. Sebaliknya, dapatkan asal API anda daripada atribut src pada elemen skrip itu sendiri. Jika widget dimuatkan dari https://cdn.staging.example.com/widget.js, panggilan API-nya harus ditetapkan secara lalai kepada https://api.staging.example.com. Jika pembangun memasukkan tag skrip ke dalam fail HTML tempatan yang dilayani dari localhost:3000, pembinaan tempatan tersebut harus menghalakan permintaan ke pelayan tempatan. Konvensyen ini menghapuskan keperluan untuk pembinaan khusus persekitaran, bendera ciri (feature flags), atau konfigurasi manual daripada pengguna sematan. Ia berfungsi dengan mudah, kerana lokasi infrastruktur tersirat melalui lokasi penghantaran.
Anggap Header Cache Seperti Talian Hayat Hotfix
Pengguna menyalin tag skrip anda sekali ke dalam templat footer mereka dan melupakannya. Anda tidak boleh menghantar e-mel kepada lima ribu peniaga dan meminta mereka mengemas kini parameter pertanyaan versi. Ini bermakna header cache anda adalah sebahagian daripada strategi tindak balas insiden anda. Tetapkan max-age yang singkat pada bundle widget anda supaya apabila anda menghantar pembaikan kritikal, ia akan tersebar dalam masa beberapa jam, bukan minggu. Kemudahan aset cache jangka panjang tidak berbaloi dengan kebuntuan apabila mengetahui beribu-ribu laman web menjalankan versi rosak yang tidak dapat anda tarik balik. Terima kos trafik CDN tersebut. Kewarasan anda bergantung padanya.
Terbalikkan CSP Anda untuk Sematan iframe
Jika anda menawarkan pilihan penyematan berasaskan iframe, Content Security Policy anda memerlukan penterbalikan daripada pemikiran aplikasi web standard. Biasanya anda mungkin melarang pembingkaian (framing) untuk mengelakkan clickjacking. Untuk widget, anda mesti membenarkannya. Tetapkan frame-ancestors * supaya mana-mana laman web boleh menghoskan iframe anda. Kemudian, jadilah sangat tegas tentang perkara lain. Perketatkan script-src, style-src, dan connect-src dengan rapi di dalam polisi iframe tersebut. Anda sengaja mendedahkan diri anda kepada web secara meluas melalui vektor pembingkaian, jadi anda mesti memastikan bahawa kod yang berjalan di dalam iframe tidak mempunyai ruang untuk menyimpang jika halaman hos cuba memanipulasinya.
Minda Tetamu
Membina sematan memerlukan pendekatan yang berbeza daripada membina aplikasi web standard. Dalam aplikasi anda sendiri, anda memiliki bekas (container), penghalaan (routing), saluran pembinaan (build pipeline), dan gaya global. Dalam sematan, anda tidak memiliki apa-apa. Halaman hos adalah rawak, sering kali lama, kadangkala tidak mesra, dan sentiasa di luar kawalan anda. Setiap andaian mestilah bersifat defensif. Nyatakan maksud anda secara eksplisit, sahkan persekitaran dengan segera, dan reka bentuk untuk kerosakan yang tidak dapat anda lihat. Widget Clanker Support berfungsi hari ini bukan kerana web ini boleh diramal, tetapi kerana kami berhenti mempercayainya untuk menjadi begitu.
