Mundarija (27)
- Bu darsda
- 1. Nega bu kerak?
- 2. Lottie: After Effects'dan JSON
- 2.1 Format
- 2.2 lottie-react 3: yangi API
- 2.3 O'lchov: kanon tajribasidagi kichik xato
- 3. dotLottie: siqilgan format va WASM pleer
- 4. Rive: interaktiv animatsiya va holat mashinasi
- 5. CSP tuzog'i: WASM qayerdan va qanday yuklanadi
- 5.1 O'lchov: uch bosqich
- 5.2 'wasm-unsafe-eval' — 'unsafe-eval' emas
- 6. Og'ir pleer: poster va kech yuklash
- 7. AutoAnimate: bitta ref bilan ro'yxat animatsiyasi
- 7.1 Qanday ishlaydi
- 7.2 O'chirish: tanish tuzoq
- 8. react-spring — qisqacha
- 9. Qaysi birini tanlash
- 10. Kanon nega olmadi — tajriba
- 11. Ko'p uchraydigan xatolar
- 12. Mashqlar
- 1-mashq (oson): qaysi direktiva?
- 2-mashq (o'rta): harakatni kamaytirgan foydalanuvchi
- 3-mashq (qiyin): CSP qatorini yasang
- 4-mashq: Vazifalar qadami — tajriba (commit yo'q)
- 13. Real ishda
- Xulosa
- Manbalar
Lottie, Rive va AutoAnimate React'da: dizayner animatsiyalari, WASM va CSP tuzog'i
Qisqacha: Lottie va Rive — dizayner chizgan animatsiyani kod yozmasdan sahifaga qo'yish usuli. Lottie — After Effects'dan eksport qilingan JSON (yoki siqilgan
.lottie), Rive — o'z muharririda chizilgan, holat mashinali interaktiv.rivfayl. AutoAnimate esa boshqa narsa: bittarefbilan ro'yxatdagi qo'shish, o'chirish va siljishni o'zi animatsiya qiladi. Tuzoq — CSP: dotLottie va Rive pleeri WebAssembly'ni CDN'dan yuklaydi. Qattiqconnect-srcvascript-srcbuni to'sadi va animatsiya jim chiqmaydi. Davosi — WASM'ni o'z serveringizdan berish va'wasm-unsafe-eval'.
Bu darsda
- Lottie, dotLottie va Rive farqini va qaysi biri qachon kerakligini tushuntirasiz.
lottie-react3 ning yangi API'si bilan animatsiya qo'yasiz va eski (v2) kodni taniysiz.- CSP ostida WASM pleer nega ishlamasligini o'lchov bilan ko'rasiz va uni tuzatasiz.
- Og'ir pleerni "poster + kech yuklash" naqshi bilan qo'shasiz va harakatni kamaytirgan foydalanuvchini hurmat qilasiz.
- AutoAnimate ichida nima borligini bilasiz va ro'yxatda u nega
AnimatePresencetuzog'ini takrorlashini ko'rasiz.
Oldin bilishingiz kerak: Motion III: chiqish va layout animatsiyalari, GSAP, Frontend xavfsizligi React'da, lazy va code splitting, Suspense.
1. Nega bu kerak?
«Bahor» ilovasiga dizayner Nilufar uchta animatsiya tayyorladi. Birinchisi — bo'sh savat: qozon ichidan bug' chiqib turadi. Ikkinchisi — "Buyurtma qabul qilindi" belgisi. Uchinchisi — bosilganda ko'z qisadigan oshpaz maskoti. Ularni Motion yoki GSAP'da qo'lda yozish — har biriga bir necha kun. Nilufar esa ularni After Effects va Rive muharririda bir soatda chizdi.
Bu dars — dizayner va dasturchi o'rtasidagi ko'prik. Dizayner fayl beradi, dasturchi uni sahifaga qo'yadi. Hayotiy o'xshatish: musiqa. Kompozitor notani yozadi (After Effects, Rive), musiqachi uni o'qib chaladi (pleer). Nota fayli kichik, lekin chaladigan asbob — pleer — og'ir bo'lishi mumkin.
Asosiy savol "qanday qo'yish" emas — u bir qator. Savol: pleer qancha turadi va xavfsizlik siyosatimizga sig'adimi? Kanon tajribasida (tajriba/kutubxonalar.txt) dotLottie va Rive vazifalar CSP'si ostida umuman ochilmadi. Biz bu tajribani Chrome 155 da qaytadan, to'liq xato matnlari bilan takrorladik va tuzatish yo'lini sinadik.
2. Lottie: After Effects'dan JSON
2.1 Format
Lottie — Airbnb chiqargan ochiq format. Dizayner After Effects'da animatsiya qiladi, Bodymovin plagini uni JSON'ga eksport qiladi. JSON ichida qatlamlar, shakllar va kalit kadrlar — rasm emas, vektor ko'rsatmalar. Shuning uchun fayl kichik va har o'lchamda tiniq.
Mana eng kichik Lottie — chapdan o'ngga suriladigan ko'k kvadrat (biz o'lchov uchun qo'lda yozganmiz, qisqartirilgan):
{
"v": "5.7.4", "fr": 30, "ip": 0, "op": 60, "w": 200, "h": 100,
"layers": [{
"ty": 4, "nm": "quti",
"ks": { "p": { "a": 1, "k": [
{ "t": 0, "s": [30, 50, 0] },
{ "t": 59, "s": [170, 50, 0] }
] } },
"shapes": [{ "ty": "rc", "s": { "a": 0, "k": [40, 40] } }]
}]
}fr — sekundiga 30 kadr, op: 60 — 60 kadr, ya'ni 2 soniya. p — o'rin (position), a: 1 — animatsiyali, k — kalit kadrlar: 0-kadrda x=30, 59-kadrda x=170. rc — to'rtburchak. Odatda bu faylni qo'lda yozmaysiz — uni dizayner beradi.
2.2 lottie-react 3: yangi API
lottie-react — eng ko'p ishlatiladigan React o'rami. Uning ichida Airbnb'ning lottie-web pleeri (5.13.0). 3-versiyada API o'zgardi:
import { Lottie } from "lottie-react";
export function EmptyCart() {
return (
<div style={{ width: 200, height: 100 }}>
<Lottie src="/animatsiyalar/bosh-savat.json" autoplay loop />
</div>
);
}import { Lottie }— nomli eksport.src— URL yoki tayyor JSON obyekti. Animatsiya o'rab turgan elementni to'ldiradi — o'lchamni o'sha elementga bering.- Eski kodda (v2) boshqacha ko'rasiz:
import Lottie from "lottie-react"vaanimationData={json}. 3.1.2 da bu ishlamaydi. Standart eksport yo'q — Vite build"default" is not exported by "node_modules/lottie-react/build/index.js"xatosini beradi. Biz buni o'z tajribamizda ko'rdik. useLottie({ src, autoplay, loop })— hook varianti:play(),seek()kabi buyruqlar.lottieInView,lottieScrollScrub— ko'ringanda o'ynash va scroll bilan boshqarish.
2.3 O'lchov: kanon tajribasidagi kichik xato
Kanon tajribasi (tajriba/kitlar/src/k/lottie.tsx) avval lottie-react 3.1.2 ni v2 uslubida yozgan edi: <Lottie animationData={anim} loop />. 3-versiyada animationData prop emas. U DOM'ga oddiy atribut bo'lib tushdi va animatsiya chizilmadi. Chrome'dagi sahifa DOM'i — div bo'sh, faqat begona atribut:
<main><div animationdata="[object Object]" class="lottie-display" style="width: 200px;"></div></main>Biz buni topdik va kanon tajribasi 3.x API (src) bilan qayta o'lchandi (lottie-qayta.txt, Chrome 155.0.8059.82): +80.2 KB, animatsiya chiziladi (SVG transform harakatda). Eski variant +80.0 KB edi — lottie-web to'plamga kirgan, lekin hech narsa chizmagan. CSP natijasini ham v3 API bilan, vazifalar CSP'si ostida tekshirdik:
## lottie.html {"svg":1,"canvas":0,"style":1}
{"csp":["style-src-elem inline"]}
## lottie-n.html {"svg":1,"canvas":0,"style":1} ← CSP'siz
{"csp":[]}Animatsiya chizildi (svg: 1) — CSP bilan ham, CSP'siz ham. Bitta buzilish: kutubxona o'z o'ramining stilini <style> teg bilan qo'shadi (@layer lottie-react{:where(.lottie-display){width:100%;height:100%;…}}). CSP uni to'sadi — natijada o'ram stilsiz qoladi. O'lchamni o'zingiz bersangiz, ko'zga farq yo'q.
Bu saboq Radix va Motion III dagi popLayout ga o'xshaydi: kutubxona "jim" <style> qo'shadi. Lekin bu yerda u faqat bezak — ishlash buzilmaydi.
Diqqat:
lottie-webAfter Effects ifodalarini (expressions — kadrlar orasida hisoblanadigan kichik JS kod)evalbilan bajaradi. Vite build buni ogohlantiradi:Use of direct eval function is strongly discouraged. CSP'da'unsafe-eval'yo'q bo'lsa, ifodali animatsiya ishlamaydi. Yechim —LottieLight(ifodasiz yengil pleer) va dizaynerdan ifodasiz eksport so'rash.
3. dotLottie: siqilgan format va WASM pleer
dotLottie (.lottie) — LottieFiles kompaniyasining formati: bir yoki bir nechta Lottie JSON va rasmlar zip ichida, ustiga tema va holat mashinasi. Fayl odatda JSON'dan ancha kichik. Pleer (@lottiefiles/dotlottie-react 0.20.0, ichida dotlottie-web 0.81.0) boshqa yo'l tanlagan. Animatsiyani JS emas, WebAssembly'ga kompilyatsiya qilingan dvigatel <canvas> ga chizadi:
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
<DotLottieReact src="/animatsiyalar/qabul.lottie" autoplay />;JS qismi kichik (+14.0 KB). Lekin dvigatel — dotlottie-player.wasm — alohida fayl: 1.24 MB, gzip bilan ~487 KB. U birinchi pleer yaratilganda CDN'dan yuklanadi.
4. Rive: interaktiv animatsiya va holat mashinasi
Rive — o'z muharriri (rive.app) va runtime'i bor platforma. Lottie "videoga o'xshash" — boshidan oxirigacha o'ynaydi. Rive esa holat mashinasi bilan ishlaydi (Holat mashinalari): animatsiya kirish qiymatlariga (hover, bosildi, daraja) javob beradi. Oshpaz maskoti sichqoncha yaqinlashsa qaraydi, bosilsa ko'z qisadi — bularni dizayner muharrirda bog'laydi, dasturchi faqat qiymat beradi:
import {
useRive,
useStateMachineInput,
} from "@rive-app/react-canvas";
export function Chef() {
const { rive, RiveComponent } = useRive({
src: "/animatsiyalar/oshpaz.riv",
stateMachines: "Asosiy",
autoplay: true,
});
const wink = useStateMachineInput(rive, "Asosiy", "kozQisish");
return (
<RiveComponent
style={{ width: 200, height: 200 }}
onClick={() => wink?.fire()}
/>
);
}Rive ham WebAssembly: rive.wasm — 1.99 MB, gzip ~810 KB, JS qismi +62.7 KB.
5. CSP tuzog'i: WASM qayerdan va qanday yuklanadi
5.1 O'lchov: uch bosqich
vazifalar ning CSP'si (Frontend xavfsizligi) — default-src 'self'; script-src 'self'; connect-src 'self'; …. dotLottie va Rive bunda nima qiladi? Uch variantni sinadik (Chrome 155.0.8059.82, Vite 8.3.3 build, har biri alohida sahifa):
| Variant | dotLottie | Rive |
|---|---|---|
| 1. Hech narsa qilmaymiz | connect-src ×4 | connect-src, script-src |
| 2. WASM o'z serverimizda | script-src (wasm-eval) ×2 |
script-src, keyin yana CDN |
3. + 'wasm-unsafe-eval' |
load, CSP 0 |
"wasm tayyor", CSP 0 |
1-variant. dotLottie WASM'ni jsdelivr'dan so'radi, keyin zaxira sifatida unpkg'dan. Ikkalasi ham to'sildi:
Connecting to 'https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-web@0.81.0/dist/dotlottie-player.wasm' violates the following Content Security Policy directive: "connect-src 'self'". The action has been blocked.Tarjimasi: "jsdelivr'dagi fayl bilan ulanish connect-src 'self' direktivasini buzadi — amal to'sildi". connect-src — fetch qayerga murojaat qila olishini belgilaydi. Pleer konsolga yozdi: dotlottie: loadError Failed to load wasm module: Error: WASM loading failed from all sources. — "WASM modulini hech bir manbadan yuklab bo'lmadi". Ekranda esa bo'sh <canvas>. Foydalanuvchi uchun bu shunchaki "animatsiya yo'q".
2-variant. WASM faylini node_modules dan o'z public/ papkamizga ko'chirdik va pleerga ko'rsatdik. Fayl yuklandi, lekin kompilyatsiya to'sildi:
WebAssembly.instantiateStreaming(): Compiling or instantiating WebAssembly module violates the following Content Security policy directive because 'unsafe-eval' is not an allowed source of script…Tarjimasi: "WebAssembly modulini kompilyatsiya qilish CSP'ni buzadi, chunki script-src da 'unsafe-eval' yo'q". Brauzer uchun WASM kompilyatsiyasi — yangi kod yaratish, xuddi eval kabi. Rive bu yerda yana bir qadam qildi: o'z WASM'i ishlamagach, jsdelivr'dagi zaxira rive_fallback.wasm ga murojaat qildi (u ham to'sildi).
3-variant. script-src 'self' 'wasm-unsafe-eval' qo'shildi. Ikkala pleer ham ishladi, CSP buzilishi — 0.
flowchart TD
A["Pleer yaratildi"] --> B{"WASM qayerdan?"}
B -- "CDN (standart)" --> C["connect-src 'self' — to'sildi"]
B -- "o'z serverimiz" --> D{"script-src da wasm-unsafe-eval?"}
D -- "yo'q" --> E["kompilyatsiya to'sildi"]
D -- "bor" --> F["animatsiya ishlaydi"]5.2 'wasm-unsafe-eval' — 'unsafe-eval' emas
Nomi qo'rqitadi, lekin farq katta. 'unsafe-eval' — JavaScript'dagi eval() va new Function() ga ruxsat. Bu XSS hujumi uchun ochiq eshik: hujumchi satrni kodga aylantira oladi. 'wasm-unsafe-eval' esa faqat WebAssembly kompilyatsiyasiga ruxsat beradi. JS eval baribir to'sig'ich ortida.
Tuzatilgan pleerlar uchun kod:
// dotLottie — birinchi pleerdan OLDIN
import { setWasmUrl } from "@lottiefiles/dotlottie-react";
setWasmUrl("/wasm/dotlottie-player.wasm");
// Rive
import { RuntimeLoader } from "@rive-app/react-canvas";
RuntimeLoader.setWasmUrl("/wasm/rive.wasm");Va CSP: script-src 'self' 'wasm-unsafe-eval'. connect-src o'zgarmaydi — fayl endi 'self' dan.
Ikki ehtiyot chorasi:
- Versiya. WASM fayli JS qismi bilan bir versiyada bo'lsin. dotLottie README'sida: har yangilanishda fayllarni o'rnatilgan paketdan qayta ko'chiring. Buni build skriptiga qo'shing, qo'lda emas.
- Zaxira CDN.
setWasmUrlaniq URL bersa, dotLottie zaxira CDN'larni o'chiradi (README). Xato yo'l jim CDN'ga emas,loadErrorga olib keladi — bu yaxshi, xato ko'rinadi.
Tekshirib ko'ring: Sardor CSP xatosini ko'rib,
connect-srcgahttps://cdn.jsdelivr.netvahttps://unpkg.comni qo'shdi. Animatsiya ishlaydimi? Bu yaxshi yechimmi?
Javob
Ishlamaydi. WASM yuklanadi, lekin kompilyatsiya script-src da to'siladi — 2-variantdagi xato. 'wasm-unsafe-eval' baribir kerak. Yechim sifatida ham yomon: ilova endi ikki begona serverga bog'liq. CDN ishlamay qolsa yoki bloklansa (O'zbekistonda ba'zi CDN'lar sekin), animatsiya yo'q. Begona domen'dan kelgan kodga ishonish — yana bir hujum yo'li. O'z serveringizdan bering.
6. Og'ir pleer: poster va kech yuklash
dotLottie va Rive pleerlari — yuzlab KB. Uni bo'sh savat rasmi uchun sahifaning birinchi yuklashiga qo'shish — LCP va INP'ga zarba. Naqsh:
- Avval poster — oddiy rasm yoki SVG, 0 KB JS.
- Pleer lazy — kerak bo'lganda (ko'rinishga kirdi, bosildi).
- Harakat kamaytirilgan bo'lsa — faqat poster.
Natija oynasida haqiqiy pleer yo'q. Uning o'rniga 200 ms da "yuklanadigan" soxta pleer — naqsh o'sha:
import { Suspense, lazy, useState } from "react";
// Soxta pleer. Haqiqiy loyihada:
// lazy(() => import("./SavatLottie"))
function FakePlayer() {
return <p>🎞️ Animatsiya o'ynayapti</p>;
}
const Player = lazy(
() =>
new Promise((resolve) =>
setTimeout(() => resolve({ default: FakePlayer }), 200),
),
);
function EmptyCart({ reduceMotion }) {
const [play, setPlay] = useState(false);
if (reduceMotion || !play) {
return (
<div>
<p role="img" aria-label="Bo'sh savat">
🧺
</p>
{!reduceMotion && (
<button onClick={() => setPlay(true)}>
Animatsiyani ko'rish
</button>
)}
</div>
);
}
return (
<Suspense fallback={<p>Yuklanmoqda…</p>}>
<Player />
</Suspense>
);
}
export default function App() {
return <EmptyCart reduceMotion={false} />;
}Ekranda:
🎞️ Animatsiya o'ynayapti- Bosishgacha — faqat poster. Pleer to'plamga ham, tarmoqqa ham kirmagan.
- Bosilgach —
Suspensefallback'i ("Yuklanmoqda…",ekran()tekshiradi), 200 ms dan keyin pleer. reduceMotionnitrueqilib ko'ring: tugma yo'qoladi, faqat poster qoladi. Loyihada bu qiymatmatchMedia("(prefers-reduced-motion: reduce)")yoki Motion'ninguseReducedMotion()idan keladi (Motion IV).
Bosish o'rniga "ko'rinishga kirganda" ham bo'ladi — useInView (Motion IV). Lekin har sahifada avtomatik yuklash — yana o'sha yuzlab KB.
7. AutoAnimate: bitta ref bilan ro'yxat animatsiyasi
7.1 Qanday ishlaydi
@formkit/auto-animate (0.10.0) — butunlay boshqa toifa. Dizayner fayli yo'q. Ota elementga ref berasiz — u bolalarning qo'shilishi, o'chirilishi va siljishini o'zi animatsiya qiladi:
import { useAutoAnimate } from "@formkit/auto-animate/react";
export function DishList({ dishes }) {
const [parent] = useAutoAnimate();
return (
<ul ref={parent}>
{dishes.map((d) => (
<li key={d.id}>{d.name}</li>
))}
</ul>
);
}Ichida nima bor? Manba kodida (index.mjs): MutationObserver — bolalar o'zgarishini kuzatadi; ResizeObserver — o'lcham; element.animate — Web Animations API bilan FLIP (Motion III dagi g'oya). Standart: 250 ms, ease-in-out. prefers-reduced-motion ni o'zi hurmat qiladi (disrespectUserMotionPreference sozlamasi bilan o'chirish mumkin). Narxi — +2.9 KB, CSP 0 (kanon tajribasi). Bir qatorlik "sehr" uchun juda arzon.
7.2 O'chirish: tanish tuzoq
React elementni o'chirdi — AutoAnimate chiqish animatsiyasini qanday qiladi? Manba kodidagi remove funksiyasi javob beradi: o'chirilgan elementni DOM'ga qaytadan qo'yadi, position: absolute va pointer-events: none bilan, animatsiya qiladi, keyin olib tashlaydi. Chrome'da o'lchadik (uch taom, birinchisi o'chiriladi):
oddiy: o'chirishdan 50 ms keyin [Osh:absolute,Lag'mon:static,Manti:static] | 450 ms [Lag'mon:static,Manti:static] | qo'shishda animatsiyalar: 4 | csp []
reduce: o'chirishdan 50 ms keyin [Lag'mon:static,Manti:static] | 450 ms [Lag'mon:static,Manti:static] | qo'shishda animatsiyalar: 0 | csp []O'chirishdan 50 ms keyin «Osh» DOM'da (absolute), state'da esa yo'q. Bu Motion III dagi AnimatePresence holatining aynan o'zi: filtr, qidiruv va testlar 250 ms davomida "o'lik" qatorni ko'radi. Bundan tashqari element React bilmagan holda DOM'ga qaytarildi. Harakat kamaytirilganda esa hammasi darhol va toza (reduce qatori).
Xulosa: AutoAnimate — kichik ro'yxatlar, sozlamalar paneli, "qo'shish-o'chirish" demolari uchun ajoyib. Testlari va filtrlari ko'p bo'lgan asosiy ro'yxat uchun — vazifalar dagi kanon yo'li: kirish animatsiyasi + o'chirishdan oldin chiqish.
8. react-spring — qisqacha
react-spring — fizikaga asoslangan (prujina) animatsiya kutubxonasi: useSpring, useTransition, useTrail hooklari. U Motion bilan bir toifada va yillar davomida mashhur bo'lgan. Eski loyihalarda, ayniqsa @react-three/fiber bilan 3D sahnalarda (keyingi dars) uchratasiz. Biz uni o'lchamadik. Yangi loyiha uchun vazifalar da Motion tanlangani — ekotizim, hujjat va LazyMotion bilan hajmni boshqarish imkoniyati sababli.
9. Qaysi birini tanlash
- AutoAnimateCSP 02,9 KB
- lottie-react 3<style> ×180,2 KB
- dotLottie (JS + WASM)14.0 + 487.4501,4 KB
- Rive (JS + WASM)62.7 + 810.2872,9 KB
Manba: Kanon o'lchovi: tajriba/kutubxonalar.txt, lottie-qayta.txt (JS) va IlmHamroh tajribasi 2026-10-17, Chrome 155.0.8059.82 (WASM gzip -9: 499 096 va 829 637 bayt)
| Vazifa | Tanlov |
|---|---|
| ro'yxat qo'shish/o'chirish, kichik UI | AutoAnimate (yoki Motion, CSS) |
| dizaynerdan oddiy illyustratsiya animatsiyasi | lottie-react — WASM yo'q, faqat <style> buzilishi |
| ko'p animatsiya, kichik fayllar, tema | dotLottie — WASM o'z serveringizdan |
| interaktiv maskot, holat mashinasi, o'yinsimon UI | Rive — eng og'ir, eng kuchli |
Muhim: WASM bir marta yuklanadi va keshlanadi. Sahifada 20 ta dotLottie bo'lsa, ~487 KB bitta marta. Bitta kichik belgi uchun esa — juda qimmat.
10. Kanon nega olmadi — tajriba
vazifalar da dizayner animatsiyasi yo'q — u ish vositasi. Bo'sh holat ikonkasi lucide SVG (Ikonkalar), yuklanish — CSS skeleton (Yuklanish holatlari). Kanon tajribasi Lottie, dotLottie va Rive'ni o'lchadi (kutubxonalar.txt) — eng kami +14.0 KB JS va qattiq CSP'da ochilmadi. AutoAnimate (+2.9 KB, CSP 0) texnik jihatdan mos edi. Lekin o'chirishda qatorni DOM'ga qaytaradi — #25 dagi o'lchov bilan rad etilgan xulq.
Bizning qo'shimcha o'lchovimiz kanon tajribasidagi bitta noaniqlikni ham ochdi: lottie.tsx v2 API'da yozilgan edi va animatsiya umuman chizilmagan. Tajriba 3.x API bilan tuzatildi va qayta o'lchandi: +80.2 KB, animatsiya chiziladi. Saboq: "o'lchandi" degan raqam ham kod haqiqatan ishlaganini isbotlamaydi — natijaga ko'z bilan qarang.
11. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
"default" is not exported by "…lottie-react…" |
v2 importi v3 bilan | import { Lottie }, src |
Lottie div bo'sh, animationdata atributi |
v2 animationData prop |
src={json} |
dotLottie/Rive — bo'sh canvas, connect-src xatosi |
WASM CDN'dan | setWasmUrl / RuntimeLoader.setWasmUrl |
Compiling … WebAssembly module violates … 'unsafe-eval' |
script-src da WASM ruxsati yo'q |
'wasm-unsafe-eval' ('unsafe-eval' emas) |
| yangilanishdan keyin pleer buzildi | eski WASM fayli, yangi JS | build'da WASM'ni paketdan ko'chirish |
| ifodali Lottie ishlamaydi | eval CSP'da to'silgan |
LottieLight, ifodasiz eksport |
| filtrda "o'lik" qatorlar | AutoAnimate o'chirilganni qaytaradi | asosiy ro'yxatda o'chirishdan oldin chiqish |
| sahifa sekin, LCP yomon | pleer birinchi yuklashda | poster + lazy |
12. Mashqlar
Mashqlar kurs/mashqlar/20/29-lottie-rive/ da.
1-mashq (oson): qaysi direktiva?
- Pleer
.wasmfaylinifetchbilan CDN'dan so'radi → - Brauzer WebAssembly modulini kompilyatsiya qilmoqchi →
- Kutubxona
<style>tegi qo'shdi →
Yechim
connect-src—fetch, XHR, WebSocket qayerga ulanadi.script-src—'wasm-unsafe-eval'kalit so'zi shu direktivaga yoziladi.style-src— konsoldagi aniq nomistyle-src-elem(stil teglari uchun) — o'lchovdagi"style-src-elem inline".
2-mashq (o'rta): harakatni kamaytirgan foydalanuvchi
«Poster va kech yuklash» bo'limidagi komponentga harakat sozlamasini qo'shing. App da «Harakatni kamaytirish» belgilash katagi (checkbox) bo'lsin, holat EmptyCart ga reduceMotion bo'lib tushsin. Katakcha belgilansa — faqat poster va Animatsiya o'chirilgan matni. Natija: katakchani belgilash.
Ishora: controlled inputlar — checked va onChange.
Yechim
import { Suspense, lazy, useState } from "react";
function FakePlayer() {
return <p>🎞️ Animatsiya o'ynayapti</p>;
}
const Player = lazy(
() =>
new Promise((resolve) =>
setTimeout(() => resolve({ default: FakePlayer }), 200),
),
);
function EmptyCart({ reduceMotion }) {
const [play, setPlay] = useState(false);
if (reduceMotion) {
return (
<p role="img" aria-label="Bo'sh savat">
🧺 Animatsiya o'chirilgan
</p>
);
}
if (!play) {
return (
<button onClick={() => setPlay(true)}>
Animatsiyani ko'rish
</button>
);
}
return (
<Suspense fallback={<p>Yuklanmoqda…</p>}>
<Player />
</Suspense>
);
}
export default function App() {
const [reduce, setReduce] = useState(false);
return (
<div>
<label>
<input
type="checkbox"
checked={reduce}
onChange={(e) => setReduce(e.target.checked)}
/>{" "}
Harakatni kamaytirish
</label>
<EmptyCart reduceMotion={reduce} />
</div>
);
}Ekranda:
Harakatni kamaytirish
🧺 Animatsiya o'chirilganHaqiqiy loyihada katakcha o'rnida tizim sozlamasi: matchMedia("(prefers-reduced-motion: reduce)").matches yoki useReducedMotion(). Ilova ichida alohida "animatsiyalarni o'chirish" sozlamasi ham foydali — ba'zi foydalanuvchilar tizim sozlamasini bilmaydi.
3-mashq (qiyin): CSP qatorini yasang
Funksiya yozing: buildCsp({ wasm, cdn }) — vazifalar CSP'sidan boshlab, kerakli ruxsatlarni qo'shadi. wasm: true — script-src ga 'wasm-unsafe-eval'. cdn — massiv: domenlar connect-src ga qo'shiladi. 'unsafe-eval' hech qachon qo'shilmasin. Direktivalar ; bilan.
Ishora: direktivalarni obyektda saqlang ({ "script-src": ["'self'"], … }), keyin Object.entries va join bilan satr yasang.
// ... funksiyangiz
console.log(buildCsp({ wasm: false, cdn: [] }));
console.log(buildCsp({ wasm: true, cdn: [] }));
const cdn = ["https://cdn.example.com"];
console.log(buildCsp({ wasm: true, cdn }));Konsolda:
default-src 'self'; script-src 'self'; style-src 'self'; connect-src 'self'
default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; connect-src 'self'
default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; connect-src 'self' https://cdn.example.comYechim
function buildCsp({ wasm, cdn }) {
const rules = {
"default-src": ["'self'"],
"script-src": ["'self'"],
"style-src": ["'self'"],
"connect-src": ["'self'", ...cdn],
};
if (wasm) rules["script-src"].push("'wasm-unsafe-eval'");
return Object.entries(rules)
.map(([name, values]) => `${name} ${values.join(" ")}`)
.join("; ");
}
console.log(buildCsp({ wasm: false, cdn: [] }));
console.log(buildCsp({ wasm: true, cdn: [] }));
const cdn = ["https://cdn.example.com"];
console.log(buildCsp({ wasm: true, cdn }));Konsolda:
default-src 'self'; script-src 'self'; style-src 'self'; connect-src 'self'
default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; connect-src 'self'
default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; connect-src 'self' https://cdn.example.comrules har chaqiruvda yangidan yasaladi — oldingi chaqiruvning push i keyingisiga "oqib" o'tmaydi. Obyekt funksiyadan tashqarida bo'lsa, ikkinchi chaqiruvdagi 'wasm-unsafe-eval' uchinchisida ikki marta chiqardi. Haqiqiy CSP'da object-src 'none', base-uri 'none', Trusted Types qatorlari ham bor — vazifalar ning vercel.json iga qarang. cdn ni qo'shish texnik jihatdan mumkin, lekin «CSP tuzog'i» bo'limidagi savolga ko'ra — o'z serveringiz yaxshiroq.
4-mashq: Vazifalar qadami — tajriba (commit yo'q)
Kanon Lottie/Rive'ni olmadi. O'z tajribangiz: vazifalar nusxasida bo'sh holatga lottie-react 3 bilan kichik animatsiya qo'ying (JSON — «Format» bo'limidagi kvadrat). npm run build va brauzer: birinchi yuklash qancha o'sdi, konsolda qanday CSP xatosi bor? So'ng uni poster + lazy naqshiga o'tkazing va qayta o'lchang.
Yechim
- To'g'ridan-to'g'ri import: birinchi yuklashga ~80 KB (kanon: +80.2). Konsolda bitta
style-src-elembuzilishi — o'ram stili. Animatsiya chiziladi. - Poster +
lazy: birinchi yuklash deyarli o'zgarmaydi. Lottie alohida chunk'ga chiqadi va faqat bosilganda yuklanadi. CSP xatosi baribir bor (o'sha<style>), lekin faqat pleer yuklanganda. - Xulosa — kanondagidek: ish vositasi uchun pleer qimmat. Nusxani o'chiring.
13. Real ishda
- Onboarding va bo'sh holatlar — "Hali buyurtma yo'q" ekranidagi jonli illyustratsiya, muvaffaqiyat belgilari. Bank va yetkazib berish ilovalarida ko'p uchraydi.
- Interaktiv maskotlar va o'yinsimon UI — Rive: tugmalar, progress, "jonli" belgilar.
- Dizayner bilan ishlash — formatni oldindan kelishing: ifodasiz Lottie, fayl hajmi chegarasi,
.lottieyoki.json. Bu sizning CSP va LCP'ingizni himoya qiladi. - Intervyu savollari: "Lottie va Rive farqi?", "
'wasm-unsafe-eval'va'unsafe-eval'farqi?", "og'ir animatsiya pleerini sahifaga qanday qo'shasiz?", "AutoAnimate o'chirishni qanday animatsiya qiladi?".
Xulosa
- Lottie — After Effects'dan JSON,
lottie-react3:import { Lottie }+src; +80 KB, CSP'da faqat o'ram<style>i to'siladi; ifodalarevaltalab qiladi. - dotLottie va Rive — WASM pleer (487 va 810 KB gzip), standartda CDN'dan. Qattiq CSP'da:
connect-src, keyinscript-srcto'sadi. - Davosi: WASM o'z serveringizdan (
setWasmUrl,RuntimeLoader.setWasmUrl) +script-src 'wasm-unsafe-eval'. Chrome o'lchovi: CSP 0, pleer ishladi. - Og'ir pleer — poster + lazy +
prefers-reduced-motion. - AutoAnimate — +2.9 KB, bitta
ref. Lekin o'chirilgan elementni DOM'ga qaytaradi — asosiy ro'yxat uchunAnimatePresencedagi tuzoq.
Keyingi dars: 3D va WebGL: Three.js va React Three Fiber — 20-qismning yakuni: 3D qachon arziydi, u +233 KB turadi va vazifalar v10 qayerga keldi.
Manbalar
- lottie-react 3.1.2 README (
import { Lottie },src, migration guide — lottiereact.com/docs/migration); lottie-web 5.13.0 - @lottiefiles/dotlottie-react 0.20.0 / dotlottie-web 0.81.0 README:
setWasmUrl, self-hosting va CSP - Rive React runtime (
@rive-app/react-canvas4.36.0):useRive,useStateMachineInput,RuntimeLoader.setWasmUrl— rive.app/docs - @formkit/auto-animate 0.10.0 manba kodi (
index.mjs:remove,MutationObserver,prefers-reduced-motion) - MDN: CSP
script-src—'wasm-unsafe-eval';connect-src— developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!