Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Qachon yuklash: uch yo'l
- 2.1 Eslab olamiz: async va defer
- 2.2 Dinamik yuklash: <script> ni JS'dan yaratish
- 2.3 Facade: avval rasm, bosilganda haqiqiysi
- 2.4 Partytown: skriptni worker'ga ko'chirish
- 3. Qayerda cheklash: iframe sandbox va CSP
- 3.1 Skript yoki iframe?
- 3.2 sandbox — React'da
- 3.3 CSP: har vidjet — yangi host
- 4. Kimdan so'rash: rozilik
- 4.1 Piksel nima
- 4.2 Rozilik → yuklash
- 5. Biz sinab ko'rdik: lite-youtube va boshqa vidjetlar CSP ostida
- 5.1 react-lite-youtube-embed
- 5.2 Boshqa vidjetlar — oldingi darslardan
- 5.3 Nega vazifalar da embed yo'q
- 6. Hujumchi nigohi
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): qaysi yo'l?
- 2-mashq (o'rta): xarita facade'i
- 3-mashq (qiyin): rozilik turlari
- 4-mashq: tajriba qadami (ixtiyoriy)
- 9. Real ishda
- Xulosa
- Manbalar
Uchinchi tomon skriptlar React'da: dinamik yuklash, facade, iframe sandbox, CSP va rozilik
Qisqacha: Chat vidjeti, piksel, YouTube va xarita — boshqa kompaniyaning kodi sizning sahifangizda. Uchta qoida: (1) kerak bo'lgandagina yuklang — dinamik
<script>, facade (avval rasm, bosilganda iframe); (2) cheklang — iframesandbox, CSP'ga faqat kerakli host; (3) so'rang — kuzatuvchi skript faqat rozilikdan keyin. Kanon tajribasi: react-lite-youtube-embed +2.6 KB, lekinvazifalarCSP'si ostida 4 ta rasm va 1 ta iframe to'sildi — CSP'ga ikki host qo'shish kerak bo'lardi.
Bu darsda
- Begona skriptni React'da bir marta va kerak bo'lganda yuklaydigan hook yozasiz.
- YouTube facade'ini React komponenti qilib,
title,loadingvasandboxbilan ulaysiz. async/defer, dinamik yuklash va Partytown qachon kerakligini ajratasiz.- Har vidjet uchun CSP'ga nima qo'shilishini va bu qanday maxfiylik narxi ekanini o'lchov bilan ko'rasiz.
- Kuzatuvchi skriptni rozilikdan keyin yuklashni yozasiz.
Oldin bilishingiz kerak: Skriptlarni ulash: defer, async, module, iframe xavfsizligi va unumdorligi, HTML darajasidagi xavfsizlik, Brauzer xavfsizlik modeli, Analitika.
1. Nega bu kerak?
Jasur aka «Bahor» saytiga to'rt narsa qo'shmoqchi: oshxona haqida YouTube video, Yandex xaritasi, onlayn yordam chati va reklama uchun piksel. To'rttasining ham "o'rnatish" yo'riqnomasi bir xil: "shu <script> ni <head> ga qo'ying".
Har biri alohida qaraganda kichik. Hammasi birga — sahifaga yuzlab kilobayt begona JS, o'nlab tashqi so'rov, va sizning nazoratingizdan tashqaridagi kod. U sekinlashtiradi, CSP'ni buzadi va mehmon haqida ma'lumot yig'adi.
Hayotiy o'xshatish: uyga mehmon chaqirish. Mehmon kerak — lekin uni qachon chaqirasiz (kerak bo'lganda), qaysi xonaga kiritasiz (cheklangan joy) va uy egasidan (mehmondan) ruxsat so'raysizmi — shuni o'zingiz hal qilasiz.
Bu darsda uchta savolga javob beramiz: qachon yuklash, qayerda cheklash va kimdan ruxsat so'rash. Facade va sandbox ni iframe xavfsizligi darsida HTML'da ko'rgan edik — u yerda va'da qilganimizdek, endi ularni JavaScript va React bilan yozamiz.
2. Qachon yuklash: uch yo'l
2.1 Eslab olamiz: async va defer
Skriptlarni ulash darsida to'rt usulni solishtirgan edik. Begona skript uchun qisqa xulosa:
| Usul | Qachon bajariladi | Begona skript uchun |
|---|---|---|
oddiy <script src> |
darhol, HTML o'qishni to'xtatadi | deyarli hech qachon |
async |
yuklanishi bilan, tartibsiz | mustaqil vidjet (analitika) |
defer |
HTML tugagach, tartib bilan | sahifaga bog'liq skript |
| dinamik (JS'dan) | siz aytganda | kerak bo'lgandagina |
Birinchi uchtasi baribir har mehmon uchun yuklanadi. Chat vidjetini 100 mehmondan 3 tasi ochadi — qolgan 97 tasi uchun u bekor yuk. To'rtinchi yo'l shu muammoni hal qiladi.
2.2 Dinamik yuklash: <script> ni JS'dan yaratish
Skriptni kodda yaratib, <head> ga qo'shsangiz — brauzer o'shanda yuklaydi. Bunday skript sukut bo'yicha async kabi ishlaydi. React'da buni hook'ga o'raymiz. Ikki talab bor:
- Bir marta. Ikki komponent bir xil skriptni so'rasa,
<head>ga ikkita teg tushmasin. - Promise. Komponent "yuklandimi?" ni kutishi kerak.
Shuning uchun yuklash modul darajasidagi xaritada eslab qolinadi — komponentlar emas, skript manzili kalit:
const yuklanganlar = new Map(); // manzil → Promise
export function skriptYukla(manzil) {
if (!yuklanganlar.has(manzil)) {
const vada = new Promise((hal, rad) => {
const s = document.createElement("script");
s.src = manzil;
s.async = true;
s.onload = () => hal();
s.onerror = () => {
yuklanganlar.delete(manzil); // keyinroq qayta urinish
rad(new Error(`Yuklanmadi: ${manzil}`));
};
document.head.append(s);
});
yuklanganlar.set(manzil, vada);
}
return yuklanganlar.get(manzil);
}Bu blok natija oynasida ishlamaydi — u yerda tarmoq yo'q, tashqi skript yuklanmaydi. Mexanizmni esa jonli ko'ramiz: script o'rniga soxta yuklovchi (setTimeout) qo'yamiz. Qolgani — xuddi shu xarita va xuddi shu hook:
import { useEffect, useState } from "react";
const yuklanganlar = new Map();
function soxtaYukla(manzil) {
if (!yuklanganlar.has(manzil)) {
console.log(`yuklanmoqda: ${manzil}`);
yuklanganlar.set(
manzil,
new Promise((hal) => setTimeout(hal, 200)),
);
}
return yuklanganlar.get(manzil);
}
function useSkript(manzil, kerak) {
const [holat, setHolat] = useState("kutmoqda");
useEffect(() => {
if (!kerak) return;
let bekor = false;
setHolat("yuklanmoqda");
soxtaYukla(manzil).then(
() => !bekor && setHolat("tayyor"),
() => !bekor && setHolat("xato"),
);
return () => {
bekor = true;
};
}, [manzil, kerak]);
return holat;
}
function Vidjet({ nom, kerak }) {
const holat = useSkript("https://example.com/chat.js", kerak);
return <p>{nom}: {holat}</p>;
}
export default function App() {
const [ochiq, setOchiq] = useState(false);
return (
<>
<button onClick={() => setOchiq(true)}>Chatni ochish</button>
<Vidjet nom="Pastki tugma" kerak={ochiq} />
<Vidjet nom="Yordam sahifasi" kerak={ochiq} />
</>
);
}Ekranda:
Chatni ochish
Pastki tugma: tayyor
Yordam sahifasi: tayyorKonsolda:
yuklanmoqda: https://example.com/chat.jsIkki komponent, bitta yuklash — konsolda bitta qator. Tugma bosilmaguncha hech narsa yuklanmadi: ikkalasi kutmoqda edi. bekor bayrog'i — komponent yuklash tugashidan oldin yo'qolsa, state yozilmasin (effektda ma'lumot olish dagi naqsh).
Maslahat: Next.js'da buning tayyor varianti bor —
next/scriptva uningstrategy(afterInteractive,lazyOnload,worker) qiymatlari. Uni 23-qismda ko'ramiz. G'oya xuddi shu: qachon yuklashni siz aytasiz.
2.3 Facade: avval rasm, bosilganda haqiqiysi
Dinamik yuklashning eng foydali turi — facade ("fasad"): og'ir vidjet o'rnida uning yengil "rasmi" turadi. Foydalanuvchi bosgandagina haqiqiy vidjet yuklanadi. iframe xavfsizligi darsida g'oyani HTML'da ko'rgandik. React komponenti:
import { useEffect, useRef, useState } from "react";
function YouTubeFasad({ id, nom }) {
const [ochiq, setOchiq] = useState(false);
const iframe = useRef(null);
useEffect(() => {
if (ochiq) console.log("iframe:", iframe.current.src);
}, [ochiq]);
if (!ochiq) {
return (
<button
className="fasad"
aria-label={`Videoni ko'rish: ${nom}`}
onClick={() => setOchiq(true)}
>
▶ {nom}
</button>
);
}
return (
<iframe
ref={iframe}
title={nom}
src={`https://www.youtube-nocookie.com/embed/${id}?autoplay=1`}
allow="autoplay; encrypted-media; picture-in-picture"
allowFullScreen
width="320"
height="180"
/>
);
}
export default function App() {
return <YouTubeFasad id="VIDEO_ID" nom="Toshkent oshi" />;
}Konsolda:
iframe: https://www.youtube-nocookie.com/embed/VIDEO_ID?autoplay=1VIDEO_ID — o'rniga haqiqiy video kodini qo'yasiz; natija oynasida tarmoq yo'q, shuning uchun iframe bo'sh qoladi. Kodda to'rt tafsilot:
- Tugma —
<div onClick>emas. Bobur Tab bilan keladi va Enter bilan ochadi (accessibility).aria-labelichida video nomi — ekran o'quvchi "Videoni ko'rish: Toshkent oshi" deydi. autoplay=1— foydalanuvchi allaqachon bir marta bosdi. Ikkinchi marta "▶" ni bosishga majburlamaymiz.youtube-nocookie.com— YouTube'ning "kengaytirilgan maxfiylik" manzili: video ijro etilmaguncha cookie qo'ymaydi (YouTube yordam sahifasi bo'yicha).title— iframe uchun majburiy (iframe): ekran o'quvchi ichki hujjatni shu nom bilan e'lon qiladi.
Haqiqiy facade'da tugma ichida muqova rasmi bo'ladi: https://i.ytimg.com/vi/<id>/hqdefault.jpg. Tayyor kutubxona — react-lite-youtube-embed — aynan shuni qiladi. Uni «Biz sinab ko'rdik» bo'limida o'lchaymiz.
Tekshirib ko'ring: Facade'dagi tugma bosilgandan keyin fokus qayerda qoladi va bu nega muammo bo'lishi mumkin?
Javob
Tugma DOM'dan olib tashlandi — uning o'rniga iframe keldi. Fokuslangan element yo'qolganda brauzer fokusni <body> ga tashlaydi. Bobur Tab bossa, sahifa boshidan boshlaydi. Yechim — iframe chizilgach unga fokus berish (iframe.current.focus() effektda) yoki tayyor kutubxonaning shu xulqini tekshirish. Bu — fokus boshqaruvi darsidagi "yo'qolgan fokus" tuzog'ining yana bir ko'rinishi.
2.4 Partytown: skriptni worker'ga ko'chirish
Ba'zi skriptni kechiktirib bo'lmaydi — masalan, analitika birinchi sahifa ko'rishni ham o'lchashi kerak. Lekin u asosiy thread'ni band qiladi va INP yomonlashadi.
Partytown g'oyasi: begona skriptni Web Worker ichida bajarish. Worker'da DOM yo'q — shuning uchun Partytown skriptning document va window ga murojaatlarini asosiy thread'ga "proksi" qiladi. Hujjat bo'yicha ulanishi — skript turini o'zgartirish:
<script
type="text/partytown"
src="https://example.com/analitika.js"
></script>text/partytown turini brauzer bajarmaydi — Partytown uni topib, worker'ga beradi. Skript window.dataLayer.push(…) kabi global funksiya chaqirsa, uni forward sozlamasida ko'rsatasiz.
Halol holat: kanon Partytown'ni o'lchamadi — hajm ham, tezlik ham, CSP natijasi ham yo'q. Sabab: u build vositasi va worker'dan DOM'ga proksi — vazifalar CSP'sida worker-src va Trusted Types bilan qanday chiqishi alohida savol. Uchinchi tomon kodi worker'da ham sizning origin'ingizda ishlaydi, faqat boshqa thread'da. Shuning uchun Partytown tezlik vositasi, xavfsizlik vositasi emas.
3. Qayerda cheklash: iframe sandbox va CSP
3.1 Skript yoki iframe?
Begona kod ikki xil keladi va xavfi turlicha:
<script> |
<iframe> |
|
|---|---|---|
| Qayerda ishlaydi | sizning sahifangizda | alohida hujjatda |
| DOM, cookie, localStorage'ga | to'liq kiradi | kirmaydi (boshqa origin) |
| Cheklash | faqat CSP va ishonch | sandbox, allow, CSP frame-src |
<script> bilan ulangan chat vidjeti localStorage dagi tokenni o'qiy oladi, forma maydonlariga yozilganini ko'radi. iframe ichidagi vidjet esa yo'q. Tanlov bo'lsa — iframe varianti xavfsizroq.
3.2 sandbox — React'da
iframe xavfsizligi darsidagi qoidalar React'da ham o'sha: bo'sh sandbox — eng qattiq, kerakli ruxsatlarni bittalab qaytarasiz. React'da atribut nomi bir xil, allowFullScreen esa camelCase:
<iframe
title="«Bahor» manzili xaritada"
src="https://example.com/xarita?nuqta=bahor"
sandbox="allow-scripts allow-popups"
loading="lazy"
referrerPolicy="no-referrer"
width="100%"
height="300"
/>allow-scripts — xarita o'z JS'ini ishlatadi. allow-popups — "Yo'nalish" tugmasi yangi oynada ochiladi. allow-same-origin YO'Q: busiz iframe o'z cookie'lariga ham kira olmaydi. allow-scripts va allow-same-origin ni birga berish xavfli juftlik — ichki sahifa o'zining sandbox atributini olib tashlay oladi (o'sha darsda ko'rganmiz). Ba'zi vidjetlar allow-same-origin siz ishlamaydi — u holda u sizning domeningizdan emas, o'z domenidan kelayotganini tekshiring.
3.3 CSP: har vidjet — yangi host
vazifalar CSP'si qattiq: default-src 'self', img-src 'self' blob:, Trusted Types. Begona vidjet qo'shish — CSP'ni kengaytirish. Qaysi direktivaga nima? Kanon har kutubxonani ikki marta ochdi: CSP bilan (nima to'sildi) va CSP'siz (qaysi hostlarga bordi). «Biz sinab ko'rdik» bo'limida aniq raqamlar. Umumiy xarita:
flowchart LR
V["Begona vidjet"] --> S["script-src: skript hosti"]
V --> C["connect-src: API so'rovlari"]
V --> I["img-src: rasmlar, piksel"]
V --> F["frame-src: iframe"]
V --> T["trusted-types: innerHTML / script URL"]
V --> ST["style-src: o'z style tegi"]Diagrammaga qarang: bitta vidjet oltita direktivaga tegishi mumkin. Har biri — "shu hostga ishonaman" degan imzo. * yoki https: kabi keng qiymat qo'yish oson, lekin u CSP'ni deyarli o'chiradi.
Tekshirib ko'ring: Chat vidjeti
script-srcgahttps://widget.example.comqo'shishni so'radi. Jasur aka "bitta host — xavfsiz" deydi. Nimani tekshirish kerak?
Javob
Uch narsa. Birinchisi — o'sha hostdagi boshqa fayllar ham endi ruxsatli: hostda foydalanuvchi yuklagan fayllar yoki eski zaif versiyalar bo'lsa, hujumchi ulardan foydalanadi. Ikkinchisi — skript qaysi boshqa hostlarga boradi (connect-src, img-src) — kanon jadvalidagi "ochiq" ustuni aynan shu. Uchinchisi — Trusted Types: skript innerHTML yoki o'zi skript yaratsa, siyosatga ham o'zgartirish kerak. "Bitta host" — faqat boshlanishi.
4. Kimdan so'rash: rozilik
4.1 Piksel nima
Piksel (tracking pixel) — reklama tizimi beradigan kichik skript yoki 1×1 o'lchamli ko'rinmas rasm. U sahifa ochilganda reklama serveriga "bu mehmon shu sahifani ko'rdi" deb xabar yuboradi. Keyin o'sha mehmonga boshqa saytlarda «Bahor» reklamasi ko'rsatiladi.
Analitika darsida rozilik qonunchiligini ko'rgandik: shaxsni boshqa saytlar bo'ylab kuzatish — rozilik talab qiladigan ish. Demak, piksel rozilikdan oldin yuklanmasligi kerak. "Yuklab, keyin o'chirib qo'yamiz" ishlamaydi — birinchi so'rov allaqachon ketgan.
4.2 Rozilik → yuklash
Yuqoridagi useSkript ning kerak parametri shu yerda ishlaydi: kerak = "foydalanuvchi rozi". Jonli model — soxta yuklovchi bilan:
import { useEffect, useState } from "react";
let yuklandi = false;
function pikselniYukla() {
if (yuklandi) return;
yuklandi = true;
console.log("piksel yuklandi");
}
export default function App() {
const [rozi, setRozi] = useState(null); // null — hali so'ralmagan
useEffect(() => {
if (rozi === true) pikselniYukla();
}, [rozi]);
return (
<>
{rozi === null && (
<section aria-label="Cookie va reklama">
<p>Reklama uchun tashriflaringizni hisoblaymizmi?</p>
<button onClick={() => setRozi(true)}>Roziman</button>{" "}
<button onClick={() => setRozi(false)}>Yo'q</button>
</section>
)}
<p>
Reklama pikseli: {rozi === true ? "yoqilgan" : "o'chiq"}
</p>
</>
);
}Ekranda:
Reklama pikseli: yoqilganKonsolda:
piksel yuklandiRozilikdan oldin ekranda savol va «o'chiq» bor edi (oraliq nuqta), piksel yuklanmagan. «Roziman» dan keyin — bitta yuklash. Uchta muhim tafsilot:
- «Yo'q» tugmasi «Roziman» bilan teng. Rad etishni yashirish ("Sozlamalar → 3 qadam → O'chirish") — qorong'i naqsh (dark pattern). Ko'p qonunlar rad etishni rozilik bilan bir xil oson bo'lishini talab qiladi.
- Tanlov saqlanadi — real loyihada
localStorageda. Har sahifada qayta so'ramang. - Rozilikni qaytarib olish — sozlamalarda. Kanonning analitika sozlamasi (Analitika) aynan shunday: o'chirilgach hech narsa yuborilmaydi.
Sukut bo'yicha null — "so'ralmagan". Uni false bilan aralashtirmang: false — "rad etdi", qayta so'ramaymiz.
5. Biz sinab ko'rdik: lite-youtube va boshqa vidjetlar CSP ostida
5.1 react-lite-youtube-embed
Kanon react-lite-youtube-embed 3.7.0 ni eng kichik misolda o'lchadi. Misol kodi (kanon):
// #27 react-lite-youtube-embed 3.7.0 (fasad: bosilmaguncha iframe yo'q)
import LiteYouTubeEmbed from "react-lite-youtube-embed";
import "react-lite-youtube-embed/dist/LiteYouTubeEmbed.css";
import { createRoot } from "react-dom/client";
createRoot(document.getElementById("ilova")!).render(<main><h1>lite-youtube</h1><LiteYouTubeEmbed id="aqz-KE-bpKQ" title="Video" /></main>);Natija (kutubxonalar-21.txt):
embed-youtube-lite JS 70426 (+ 2.6 KB) CSS 1308 | CSP img-src×4,frame-src×1 | xato: Loading the image 'https://i.ytimg.com/vi/aqz-KE-bpKQ/hqdefault.jpg' violates the following Content ; Loading the image 'https://i.ytimg.com/vi/aqz-KE-bpKQ/hqdefault.jpg' violates the following Content | ochiq: tashqi fonts.gstatic.com,i.ytimg.com,www.youtube-nocookie.comUni o'qiymiz:
- Hajm — +2.6 KB JS va 1.3 KB CSS. Arzon: YouTube pleyerining o'zi bosilgunga qadar umuman yuklanmaydi.
- CSP bilan — 5 ta buzilish.
img-src×4: muqova rasmii.ytimg.comdan (ikki marta) va ikkidata:rasm (ijro belgisi SVG va soya PNG).frame-src×1: bosilgachyoutube-nocookie.comiframe'i to'sildi. - CSP'siz — sahifa uch hostga bordi:
i.ytimg.com,www.youtube-nocookie.comvafonts.gstatic.com(Google shriftlari — iframe ichidan).
Demak, vazifalar ga video qo'shish uchun CSP shunday kengayardi:
img-src 'self' blob: data: https://i.ytimg.com;
frame-src https://www.youtube-nocookie.com;data: rasmlarga ruxsat — kutubxona ikonkalari uchun. Uning o'rniga ikonkani o'z CSS'ingizda bersangiz ham bo'ladi.
Maxfiylik narxi: muqova rasmi ham Google serveridan keladi. Ya'ni bosilmagan video ham mehmonning IP manzilini Google'ga ko'rsatadi. Iloji bo'lsa muqovani o'z serveringizga ko'chiring. Bosilgandan keyin esa — Google bilan to'g'ridan-to'g'ri aloqa, nocookie bo'lsa ham.
5.2 Boshqa vidjetlar — oldingi darslardan
Shu qismda kanon o'nlab tashqi kutubxonani xuddi shu usulda o'lchadi. Uchinchi tomon nuqtai nazaridan xulosa:
| Vidjet | Nima to'sildi | Dars |
|---|---|---|
| posthog (analitika) | TrustedScriptURL — skript yuklaydi | Analitika |
| Turnstile, reCAPTCHA, hCaptcha | TrustedScriptURL; hCaptcha 5 host | CAPTCHA |
| Monaco muharriri | jsDelivr CDN'dan yuklaydi | Muharrirlar |
| Leaflet, MapLibre | innerHTML / worker; plitka hostlari | Xaritalar |
Umumiy qonuniyat: skript yuklaydigan vidjetlar (CAPTCHA, analitika SDK, Monaco) Trusted Types'da TrustedScriptURL buzilishini beradi. Ular uchun CSP'ga host qo'shishning o'zi yetmaydi — Trusted Types siyosatiga ham o'zgartirish kerak. Bu — eng qimmat kengaytirish.
5.3 Nega vazifalar da embed yo'q
Bu darsda vazifalar kodi o'zgarmaydi. Ilovada video ham, xarita ham, chat vidjeti ham yo'q — qo'shish uchun sabab yo'q. Analitika va xatolar kuzatuvi esa kanonda o'zimizniki (Analitika, Xatolarni kuzatish) — begona skriptsiz, CSP o'zgarmagan. Saboq: eng arzon uchinchi tomon skripti — qo'shilmagani.
6. Hujumchi nigohi
Ta'minot zanjiri. Begona skript sizning sahifangizda sizning huquqlaringiz bilan ishlaydi. Skriptlarni ulash darsidagi polyfill.io voqeasini eslang: 2024-yilda domen yangi egaga o'tdi va 100 mingdan ortiq saytda zararli kod ishladi. Sayt egalari hech narsani o'zgartirmagan edi.
Himoya qatlamlari:
- Kamroq skript. Har yangi vidjetdan oldin: "busiz bo'ladimi?"
- SRI (
integrity) — fayl bir xil bo'lsa (HTML xavfsizligi). Chat va analitika SDK'lari ko'pincha har safar yangi versiya beradi — ularga SRI qo'yib bo'lmaydi. - iframe varianti — mavjud bo'lsa,
<script>o'rniga. Iframe sizning DOM valocalStoragega kira olmaydi. - CSP — aniq hostlar,
*emas. Trusted Types —innerHTMLva skript manzillarini nazorat qiladi. - Rozilik — kuzatuvchi kod foydalanuvchi rozi bo'lmaguncha umuman yuklanmaydi.
Forma ma'lumoti. <script> bilan ulangan vidjet sahifadagi har maydonni o'qiy oladi — parol va karta raqami ham. Shuning uchun to'lov va kirish sahifalarida begona skript bo'lmasligi kerak. Analitika bo'lsa ham — o'sha sahifalardan olib tashlang.
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
<head> da bir skript ikki marta |
har komponent o'zi script qo'shadi |
modul darajasidagi xarita (Map) |
konsolda Refused to load the script |
CSP'da host yo'q | ataylab qo'shing yoki vidjetdan voz keching |
| video bosilsa ham ochilmaydi | frame-src yo'q |
frame-src https://www.youtube-nocookie.com |
| piksel rozilikdan oldin so'rov yubordi | <head> dagi statik <script> |
rozilikdan keyin dinamik yuklash |
| iframe ekran o'quvchida "frame" deb o'qiladi | title yo'q |
title majburiy |
sandbox bilan vidjet buzildi |
kerakli ruxsat yo'q | bittalab qo'shing; allow-same-origin + allow-scripts ga ehtiyot |
8. Mashqlar
Mashqlar kurs/mashqlar/21/27-uchinchi-tomon/ da.
1-mashq (oson): qaysi yo'l?
To'ldiring (async, defer, dinamik, facade, iframe):
- Analitika — sahifaga bog'liq emas, imkon qadar erta:
- Chat vidjeti — faqat "Yordam" tugmasi bosilganda:
- YouTube video — bosilmaguncha faqat rasm:
- Begona to'lov formasi — sahifangiz DOM'iga kira olmasin:
- O'z skriptingiz, HTML tayyor bo'lgach, tartib bilan:
Yechim
- async — mustaqil, tartib muhim emas; lekin kuzatuvchi bo'lsa — rozilikdan keyin.
- dinamik — 97% mehmon uchun yuklanmaydi.
- facade — pleyer kodi faqat bosilganda.
- iframe — boshqa origin: sizning DOM, cookie va
localStoragega yo'l yo'q. - defer — HTML o'qilib bo'lgach, yozilgan tartibda.
2-mashq (o'rta): xarita facade'i
«Bahor» manzili uchun facade yozing:
- Avval tugma: «Xaritani ochish: Chilonzor filiali».
- Bosilganda
<iframe>—title="«Bahor» Chilonzor filiali xaritada",src—https://example.com/xarita?filial=chilonzor,sandbox="allow-scripts allow-popups",loading="lazy". - Iframe chizilgach unga fokus berilsin va konsolga
fokus: IFRAMEyozilsin.
Ishora: useRef + useEffect — «Facade» bo'limidagi kabi. Fokusni tekshirish — document.activeElement.tagName.
Yechim
import { useEffect, useRef, useState } from "react";
function XaritaFasad({ filial, nom }) {
const [ochiq, setOchiq] = useState(false);
const iframe = useRef(null);
useEffect(() => {
if (!ochiq) return;
iframe.current.focus();
console.log("fokus:", document.activeElement.tagName);
}, [ochiq]);
if (!ochiq) {
return (
<button onClick={() => setOchiq(true)}>
Xaritani ochish: {nom}
</button>
);
}
return (
<iframe
ref={iframe}
title={`«Bahor» ${nom} xaritada`}
src={`https://example.com/xarita?filial=${filial}`}
sandbox="allow-scripts allow-popups"
loading="lazy"
width="320"
height="200"
/>
);
}
export default function App() {
return <XaritaFasad filial="chilonzor" nom="Chilonzor filiali" />;
}Konsolda:
fokus: IFRAMETugma yo'qolgach fokus <body> ga tushmadi — iframe'ga o'tdi. title da filial nomi bor: bir sahifada bir nechta xarita bo'lsa, ekran o'quvchi ularni ajratadi.
3-mashq (qiyin): rozilik turlari
Ikki turdagi skript bor: «Statistika» (o'z analitikangiz) va «Reklama» (piksel). Komponent yozing:
- Ikki katakcha (checkbox) — sukut bo'yicha ikkalasi ham belgilanmagan — va «Saqlash» tugmasi.
- «Saqlash» bosilganda faqat belgilanganlar "yuklanadi": konsolga
yuklandi: statistikava/yokiyuklandi: reklama. - Har tur bir martadan ortiq yuklanmasin (ikki marta «Saqlash» bosilsa ham).
- Ostida holat:
Statistika: ha, Reklama: yo'qko'rinishida.
Ishora: yuklanganlar — modul darajasidagi Set. Katakcha holati — useState, saqlangan tanlov — alohida state.
Yechim
import { useEffect, useState } from "react";
const yuklangan = new Set();
function yukla(tur) {
if (yuklangan.has(tur)) return;
yuklangan.add(tur);
console.log(`yuklandi: ${tur}`);
}
export default function App() {
const [tanlov, setTanlov] = useState({
statistika: false,
reklama: false,
});
const [saqlangan, setSaqlangan] = useState(null);
useEffect(() => {
if (saqlangan === null) return;
for (const [tur, ha] of Object.entries(saqlangan)) {
if (ha) yukla(tur);
}
}, [saqlangan]);
const belgi = (tur) => (
<label>
<input
type="checkbox"
checked={tanlov[tur]}
onChange={(e) =>
setTanlov({ ...tanlov, [tur]: e.target.checked })
}
/>
{tur === "statistika" ? "Statistika" : "Reklama"}
</label>
);
const soz = (x) => (x ? "ha" : "yo'q");
return (
<>
{belgi("statistika")} {belgi("reklama")}{" "}
<button onClick={() => setSaqlangan({ ...tanlov })}>
Saqlash
</button>
<p>
Statistika: {soz(saqlangan?.statistika)}, Reklama:{" "}
{soz(saqlangan?.reklama)}
</p>
</>
);
}Konsolda:
yuklandi: statistikaEkranda:
Statistika Reklama Saqlash
Statistika: ha, Reklama: yo'q«Saqlash» ikki marta bosildi, lekin Set tufayli statistika bir marta yuklandi. { ...tanlov } — har bosishda yangi obyekt, shuning uchun effekt qayta ishlaydi; takrorni Set to'xtatadi. Reklama belgilanmadi — uning kodi umuman yuklanmadi.
4-mashq: tajriba qadami (ixtiyoriy)
vazifalar da alohida branch oching (masalan tajriba/youtube) va bitta sahifaga react-lite-youtube-embed qo'shing. npm run build va npm run preview bilan oching, DevTools Console'da CSP xabarlarini sanang. Keyin index.html dagi CSP'ga «Biz sinab ko'rdik» bo'limidagi ikki qatorni qo'shib, qayta tekshiring. Branch'ni main'ga qo'shmang — o'chiring.
Yechim
Kutiladigan natija (kanon o'lchovi bilan bir xil bo'lishi kerak):
- CSP'siz o'zgarishda — Console'da
Loading the image 'https://i.ytimg.com/…' violates …(rasm) xabarlari; bosilgachFraming 'https://www.youtube-nocookie.com/' violates …. - Ikki qator qo'shilgach — muqova ko'rinadi, bosilganda video ochiladi.
npm run build— sahifa chunk'i ~2.6 KB ga, CSS ~1.3 KB ga oshadi.- Network panelida — bosilmaguncha
youtube-nocookie.comga so'rov yo'q (facade ishlayapti), lekini.ytimg.comga bor.
9. Real ishda
- Marketing va dasturchi orasidagi bahs — har loyihada. "Shu pikselni qo'yib bering" iltimosiga to'g'ri javob: "qaysi sahifaga, rozilikdan keyin, CSP'ga shu hostlar qo'shiladi, narxi shuncha KB". Raqam bilan gapiring.
- Tag manager (Google Tag Manager kabi) — marketologlar dasturchisiz skript qo'shadigan vosita. Qulay, lekin CSP nuqtai nazaridan "har qanday skript" degani. Uni ulash — jamoa qarori.
- Intervyu savollari: "facade nima?", "
asyncvadeferfarqi?", "begona skriptni qanday xavfsiz ulaysiz?", "iframesandboxda qaysi juftlik xavfli?".
Xulosa
- Begona skript — sizning sahifangizda, sizning huquqlaringiz bilan. Har birini o'lchang: KB, hostlar, CSP buzilishlari.
- Qachon:
async/defer— har mehmonga; dinamik yuklash va facade — faqat kerak bo'lganda. Bir marta yuklash — modul darajasidagiMap. - Qayerda: iframe skriptdan xavfsizroq;
sandbox— minimal ruxsat; CSP — aniq hostlar. - Kimdan: kuzatuvchi kod — rozilikdan keyin; «Yo'q» «Roziman» bilan teng.
- Kanon: lite-youtube +2.6 KB, lekin CSP'ga
i.ytimg.com,data:vayoutube-nocookie.comkerak; Partytown o'lchanmadi.
Keyingi dars: PWA React loyihada: vite-plugin-pwa, Workbox va Serwist — o'z sw.js imizni ikki tayyor kutubxona bilan o'lchab solishtiramiz va deploydan keyingi yashirin xatoni tuzatamiz.
Manbalar
- MDN:
<script>(async,defer),HTMLScriptElement,<iframe>sandbox, Content-Security-Policy (frame-src,img-src,trusted-types) - web.dev: "Lazy load third-party resources with facades"; "Efficiently load third-party JavaScript"
- YouTube yordam markazi: kengaytirilgan maxfiylik rejimi (
youtube-nocookie.com) - Partytown hujjati:
type="text/partytown",forward - Kanon:
natijalar/tajriba/kutubxonalar-21.txt,tajriba/kutubxonalar/src/k/embed-youtube-lite.tsx(2026-10-17)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!