IlmHamroh
JavaScript Full-stack/23-qism. Next.js32/43-dars15 daqiqa
Mundarija (31)

next/font va next/script: o'z shriftingiz, zaxira shrift va 3-tomon skriptlar

Qisqacha: next/font shriftni build vaqtida loyihaning o'ziga ko'chiradi (/_next/static/media/) va brauzerga preload ishorasini beradi. U o'lchamlari moslangan zaxira shrift ham yasaydi — shrift yuklanganda matn sakramaydi (CLS 0). next/font/google ham shriftni Google'dan build vaqtida oladi, brauzer Google'ga bormaydi; lekin build uchun internet kerak. next/font/local — o'z faylingiz. next/script 3-tomon skriptlarni to'g'ri vaqtda yuklaydi: afterInteractive (sukut), lazyOnload, beforeInteractive.

Bu darsda

  • next/font/local bilan v1 dagi Rubik shriftini portfolio ga qaytarasiz va Next yasagan haqiqiy CSS'ni o'qiysiz.
  • Zaxira shrift (size-adjust) CLS'ni qanday yo'qotishini tushuntirasiz.
  • next/font/google va local farqini kanon tajribasi bilan bilasiz: internetsiz build yiqiladi.
  • OG rasmlarga shrift berasiz va DataView xatosining sababini jonli ko'rasiz.
  • next/script strategiyalarini va @next/third-parties ni bilasiz.

Oldin bilishingiz kerak: next/image, Veb-shriftlar, SEO fayllari va OG rasmlar, Core Web Vitals, Uchinchi tomon skriptlar.

1. Nega bu kerak?

v1 saytida sarlavhalar Rubik shriftida edi (Veb-shriftlar darsida @font-face bilan ulangan). portfolio v2 hozircha tizim shriftida — Layout darsida "Rubik next/font darsida qaytadi" degan edik.

Oddiy @font-face ning uchta muammosi bor:

  1. Kech topilish. Brauzer shriftni CSS'ni yuklab, tahlil qilib, matnni ko'rgandagina so'raydi. Shrift kechikadi.
  2. Sakrash. Avval zaxira shrift (Arial) chiziladi, keyin Rubik keladi. Harflar kengligi boshqa — qatorlar siljiydi (CLS).
  3. Tashqi server. fonts.googleapis.com dan ulansa — brauzer har tashrifda Google'ga so'rov yuboradi (maxfiylik), Google ishlamasa — shrift yo'q.

next/font uchalasini build vaqtida hal qiladi. Hayotiy o'xshatish: to'y uchun stullar. @font-face — mehmonlar kelgandan keyin stul qidirish. next/font — stullarni oldindan olib kelib, ularning joyiga xuddi shunday o'lchamdagi vaqtinchalik o'rindiq qo'yish: almashtirilganda hech kim joyidan siljimaydi.

2. next/font/local

2.1 Kanondagi kod

src/shriftlar/index.ts (holat 32):

ts
import localFont from "next/font/local";

export const sarlavhaShrifti = localFont({
  src: "./rubik-latin-wght.woff2",
  weight: "300 900",
  display: "swap",
  variable: "--shrift-rubik",
  adjustFontFallback: "Arial",
});
Variant Ma'nosi
src shrift fayli — shu papkada, Fontsource'dan (Rubik 5.3.0, lotin qismi, 35 348 B)
weight: "300 900" variable font — bitta faylda 300 dan 900 gacha hamma qalinlik
display: "swap" shrift kelguncha zaxira bilan ko'rsat (C-31 dagi font-display)
variable CSS o'zgaruvchi nomi — CSS'da shriftni shu orqali ishlatamiz
adjustFontFallback zaxira shriftni qaysi tizim shriftidan moslab yasash

Shrift litsenziyasi — SIL OFL 1.1: OFL.txt fayli yonida turadi (litsenziya shuni talab qiladi). Variable font (o'zgaruvchan shrift) — har qalinlik uchun alohida fayl o'rniga bitta fayl: kanon 300–900 ni bitta 35 KB faylda oldi.

next/font funksiyalari modul darajasida chaqiriladi (komponent ichida emas) — Next ularni build vaqtida statik tahlil qiladi.

2.2 Ulash

Root layout'da <html> ga o'zgaruvchi klassi:

tsx
import { sarlavhaShrifti } from "@/shriftlar";

<html
  lang="uz"
  className={sarlavhaShrifti.variable}
  suppressHydrationWarning
>

globals.css dagi bitta qator o'zgardi:

diff
-    --shrift-sarlavha: var(--shrift-matn);
+    --shrift-sarlavha: var(--shrift-rubik), var(--shrift-matn);

v1 tokenlari (dizayn tizimi) shu yerda yashaydi: sarlavhalar --shrift-sarlavha ni ishlatadi, endi u Rubik'ni oladi. Hech bir komponent o'zgarmadi.

2.3 Next nima yasadi — haqiqiy CSS

Build'dan keyin .next/static/chunks/ dagi CSS faylida (holat 32 nusxasi, biz ishga tushirdik; qatorlarga bo'lindi):

text
@font-face{font-family:sarlavhaShrifti;src:url(../media/rubik_latin_wght-s.p.2hiny1627tgmp.woff2)format("woff2");font-display:swap;font-weight:300 900}
@font-face{font-family:sarlavhaShrifti Fallback;src:local(Arial);ascent-override:91.09%;descent-override:24.36%;line-gap-override:0.0%;size-adjust:102.64%}
._3Uyl2a_className{font-family:sarlavhaShrifti,sarlavhaShrifti Fallback}
._3Uyl2a_variable{--shrift-rubik:"sarlavhaShrifti", "sarlavhaShrifti Fallback"}

Qatorma-qator:

  1. Rubik — endi /_next/static/media/ dan. Fayl nomidagi s.p — "subset, preload": oldindan yuklanadi. Oila nomi — sarlavhaShrifti: Next eksport qilingan o'zgaruvchi nomini oldi.
  2. Zaxira shrift — oddiy Arial, lekin to'rtta tuzatish bilan: size-adjust: 102.64% — Arial harflarini 2.64% kattalashtir; ascent-override, descent-override — qator balandligini Rubik'nikiga tenglashtir. Natija: Arial Rubik bilan bir xil joy egallaydi.
  3. className — shriftni to'g'ridan qo'llash uchun.
  4. variable — biz ishlatgan klass: --shrift-rubik o'zgaruvchisini e'lon qiladi.

Vaqt bo'yicha shunday:

sequenceDiagram
  participant B as Brauzer
  participant S as Server
  B->>S: HTML so'rovi
  S-->>B: HTML + font preload ishorasi
  B->>S: rubik…woff2 (darhol)
  Note over B: matn "sarlavhaShrifti Fallback" bilan
  S-->>B: Rubik keldi (swap)
  Note over B: harf shakli o'zgardi, joy — yo'q

Ikkinchi qator — butun hiylaning yuragi. Shrift kelguncha matn "Rubik o'lchamidagi Arial" bilan chiziladi; Rubik kelganda harflar shakli o'zgaradi, lekin qatorlar siljimaydi. Kanon o'lchovi: CLS 0.

Preload — HTML'ga RSC ma'lumoti ichida ishora sifatida tushdi (/loyihalar/vazifalar sahifasidan ko'chirma):

text
:HL[\"/_next/static/media/rubik_latin_wght-s.p.2hiny1627tgmp.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]

HL — "hint link": React buni brauzerda <link rel="preload" as="font"> ga aylantiradi. Kanon Chrome o'lchovida preload ro'yxatida shrift bor edi (32-rasm-keyin.txt), h1 shrift steki: sarlavhaShrifti, "sarlavhaShrifti Fallback", system-ui, ….

Narxi: har sahifa boshiga +34.5 KB shrift (tekshiruv-32.txt), JS o'zgarmadi, CSS 2.2 → 2.4 KB.

Tekshirib ko'ring: Nega zaxira shrift uchun Arial, Georgia emas? adjustFontFallback ni nima belgilaydi?

Javob

Zaxira asosiy shriftga shakl jihatidan yaqin bo'lishi kerak. Rubik — tirnoqsiz (sans-serif), Arial ham. Georgia tirnoqli (serif) — size-adjust bilan o'lchamni tenglashtirsa ham, harflar juda boshqacha ko'rinib, almashish sezilardi. next/font/local da adjustFontFallback: "Arial" (sukut) yoki "Times New Roman" (serif shriftlar uchun) yoki false.

3. next/font/google — kanon tajribasi

3.1 Qanday ishlaydi

tsx
import { Rubik } from "next/font/google";

const rubik = Rubik({
  subsets: ["latin", "cyrillic"],
  variable: "--shrift-rubik",
});

Nomi "google" bo'lsa ham, brauzer Google'ga bormaydi: Next shriftni build vaqtida yuklab, o'z serveringizga qo'yadi. subsets — qaysi harflar to'plami: o'zbek lotini uchun latin yetarli (o', g' — oddiy harf + apostrof), rus tili uchun cyrillic.

Kanon buni sinab ko'rdi (natijalar/tajriba/32-next-font-google.txt). Internet bor — build 28 s, .next/static/media da 6 ta fayl:

text
32480 098850a6eb1f8577-s.1e7lfzpvfrh7f.woff2
15108 21445b8bd0ec5702-s.1n1ntp5se85-_.woff2
12288 6dac7af80352e41b-s.1-avrnevmoafi.woff2
9352 87c7f5b5afcd23bd-s.0kf5m0zv7sxld.woff2
35324 c9f6ebf08ddd616b-s.p.0sv86lbjkn8rn.woff2
19288 d25394c5b8ff78eb-s.0ongx-zmnmtio.woff2

Google shriftni bir nechta qismga (subset) bo'lib beradi: lotin, kengaytirilgan lotin, kirill va boshqalar. s.p — faqat bittasi (lotin) preload qilinadi, qolganlari sahifada shunday harf uchrasagina yuklanadi (unicode-range).

3.2 Internetsiz — build yiqildi

Endi tarmoq yo'qligini taqlid qildik (HTTPS_PROXY ni ishlamaydigan manzilga):

text
Warning: Error while requesting resource
There was an issue establishing a connection while requesting https://fonts.googleapis.com/css2?family=Rubik:wght@300..900&display=swap
> Build error occurred
Error: Turbopack build failed with 1 error:

Build to'xtadi. CI serverida Google'ga kirish cheklangan bo'lsa yoki Google javob bermasa — deploy ham to'xtaydi. Kanon qarori — local:

next/font/google next/font/local
Fayl qayerdan build'da Google'dan repodagi fayl
Build internetsiz yiqiladi ishlaydi
Brauzer Google'ga boradimi yo'q yo'q
Qulaylik bitta qator faylni o'zingiz olasiz (Fontsource)

4. OG rasmlarga shrift va DataView tuzog'i

4.1 Muammo

Oldingi darsda OG rasmdagi sarlavha qalin chiqmagan edi — satori'da shrift yo'q edi. Endi Rubik bor. Lekin satori woff2 ni o'qimaydi (faqat ttf, otf, woff). Shuning uchun kanon OG uchun Rubik'ning ikkita .woff faylini qo'shdi (400 va 700) va ularni o'qiydigan yordamchi yozdi (src/shriftlar/og.ts, birinchi variant — soddalashtirilgan):

ts
async function faylniOqi(nom: string): Promise<Uint8Array> {
  "use cache";
  cacheLife("max");
  return new Uint8Array(
    await readFile(path.join(process.cwd(), "src", "shriftlar", nom)),
  );
}

// ImageResponse'ga:
// fonts: [{ name: "Rubik", data: await faylniOqi(…) }]

Fayl o'qish Cache Components'da "keshlanmagan ma'lumot" — shuning uchun "use cache" (Cache Components I): build vaqtida bir marta o'qiladi. Build esa to'xtadi:

text
TypeError: First argument to DataView constructor must be an ArrayBuffer

Tarjimasi: "DataView konstruktorining birinchi argumenti ArrayBuffer bo'lishi kerak".

4.2 Sabab — natija oynasida

Uint8Array — baytlar "oynasi" (view), ArrayBuffer esa baytlarning o'zi saqlanadigan xotira bo'lagi (ArrayBuffer va typed array). Satori shrift baytlarini new DataView(...) bilan o'qiydi va unga ArrayBuffer kerak. Keshdan esa Uint8Array qaytdi. Bir xil xatoni brauzerda ham olamiz:

js
const baytlar = new Uint8Array([0x77, 0x4f, 0x46, 0x46]); // "wOFF"

try {
  new DataView(baytlar);
} catch (e) {
  console.log(`${e.name}: ${e.message}`);
}

const buf = baytlar.slice().buffer;
const dv = new DataView(buf);
console.log(buf instanceof ArrayBuffer, dv.byteLength);
console.log(dv.getUint32(0).toString(16)); // 774f4646

Konsolda:

text
TypeError: First argument to DataView constructor must be an ArrayBuffer
true 4
774f4646

.slice() — massivning nusxasi, o'z alohida xotirasi bilan. .buffer — shu xotiraning ArrayBuffer i. 774f4646 — wOFF, woff fayllarining birinchi to'rt bayti (fayl "imzosi").

4.3 Nega aynan .slice().buffer

Nega shunchaki baytlar.buffer emas? Chunki Uint8Array kattaroq xotiraning bir bo'lagiga qarashi mumkin. Node'dagi Buffer (u ham Uint8Array) kichik ma'lumotlar uchun umumiy "hovuz" xotirasidan joy oladi:

js
const b = Buffer.from("Rubik");
console.log(b.byteLength); // 5
console.log(b.buffer.byteLength > b.byteLength); // true
console.log(new Uint8Array(b).buffer.byteLength); // 5

b.buffer — 5 bayt emas, butun hovuz (Node 24 da biz o'lchaganda 65 536 bayt). Uni satori'ga bersak, shrift o'rniga begona baytlarni o'qirdi. Kanon yechimi Uint8Array.prototype.slice() — aniq o'z baytlari bilan yangi xotira:

ts
// Keshdan Uint8Array qaytadi, satori esa ArrayBuffer kutadi
// ("First argument to DataView constructor must be an ArrayBuffer")
async function arrayBuffer(nom: string): Promise<ArrayBuffer> {
  const b = await faylniOqi(nom);
  return b.slice().buffer;
}

Diqqat: Node Buffer da .slice() nusxa qilmaydi (u subarray kabi o'sha xotiraga qaraydi). Kanon kodida b — Uint8Array (faylniOqi uni new Uint8Array(...) bilan nusxalab qaytaradi), shuning uchun .slice() haqiqiy nusxa. Buffer bilan ishlasangiz — avval new Uint8Array(buffer).

Tuzatishdan keyin build o'tdi: ○ /opengraph-image 30d 1y — rasm endi shrift keshiga bog'langan, sarlavha qalin.

4.4 ImageResponse ga shrift

tsx
return new ImageResponse(<div>…</div>, {
  ...size,
  fonts: await ogShriftlari(),
});

ogShriftlari() — ikki obyekt: { name: "Rubik", data, weight: 400 } va weight: 700. JSX'dagi fontWeight: 700 endi haqiqiy qalin faylni topadi.

5. next/script

5.1 Strategiyalar

3-tomon skriptlar (analitika, chat vidjeti, to'lov tugmasi) — Uchinchi tomon skriptlar darsidagi narx va maxfiylik muammolari Next'da ham o'sha. next/script faqat qachon yuklashni boshqaradi:

strategy Qachon Misol
beforeInteractive Next kodidan oldin; faqat root layout'da bot himoyasi, cookie roziligi
afterInteractive (sukut) sahifa jonlangach analitika, teg menejeri
lazyOnload brauzer bo'sh qolganda chat vidjeti, ijtimoiy tarmoq tugmalari
worker web worker'da (Partytown) eksperimental, App Router'da ishlamaydi (hujjat)
tsx
import Script from "next/script";

<Script
  src="https://example.com/chat.js"
  strategy="lazyOnload"
  onLoad={() => console.log("chat tayyor")}
/>

Ichki skript ham yozish mumkin — id bilan (Next uni bir marta ishga tushirish uchun kuzatadi). onLoad, onReady, onError — faqat client komponentda (funksiya brauzerda kerak).

5.2 @next/third-parties

Mashhur xizmatlar uchun tayyor komponentlar: GoogleTagManager, GoogleAnalytics, YouTubeEmbed, GoogleMapsEmbed. Ular skriptni optimal strategiya bilan ulaydi. Hujjat ochiq aytadi: kutubxona hali eksperimental.

5.3 portfolio da — yo'q

Kanonda 3-tomon skript yo'q: analitika hisobi va kaliti yo'q, va CSP script-src 'self' qoidasi tashqi skriptlarni baribir to'sadi. Shu bo'lim — hujjat bo'yicha, o'lchanmagan. Tashqi skript qo'shsangiz, ikki ishni qiling: CSP'ga domenni qo'shing va maxfiylik siyosatini yangilang (rozilik — 21-qism saboqlari).

Tekshirib ko'ring: Chat vidjeti uchun beforeInteractive tanlandi — "tez yuklansin". Nima noto'g'ri?

Javob

Chat sahifaning asosiy vazifasi emas — foydalanuvchi uni darhol ishlatmaydi. beforeInteractive uni sahifaning o'z kodidan oldin yuklaydi va muhim JS navbatini sekinlatadi. To'g'ri tanlov — lazyOnload: sahifa tayyor, brauzer bo'sh — keyin chat. beforeInteractive — faqat sahifa ishlashi uchun oldin bo'lishi shart bo'lgan narsalar.

6. Tailwind bilan

Tailwind v4 ishlatilsa, shrift o'zgaruvchisi tema tokeniga ulanadi:

css
@theme inline {
  --font-sarlavha: var(--shrift-rubik);
}

Keyin font-sarlavha utility klassi Rubik'ni beradi. portfolio da Tailwind yo'q — nega, keyingi darsda o'lchov bilan.

7. Portfolio qadami: Rubik va commit

7.1 Fayllar (holat 32)

Fayl O'zgarish
src/shriftlar/rubik-latin-wght.woff2 + OFL.txt Fontsource Rubik 5.3.0, lotin, variable
src/shriftlar/index.ts localFont — sarlavhaShrifti
src/shriftlar/og.ts + rubik-latin-400.woff, -700.woff OG shriftlari, "use cache", .slice().buffer
app/layout.tsx <html className={sarlavhaShrifti.variable}>
app/globals.css --shrift-sarlavha: var(--shrift-rubik), …
ikki opengraph-image.tsx fonts: await ogShriftlari()
loyihalar/[slug]/page.tsx, proxy.ts preload, matcher (next/image)

7.2 Tekshiruv va commit

bash
npm run lint
npm run tip
npm run build
npm run start

/opengraph-image ni oching — sarlavha qalin. Sahifada DevTools → Elements → h1 → Computed → font-family. Kanon o'lchovi: JS 146.5 KB (o'zgarmadi), CSS 2.2 → 2.4 KB, shrift +34.5 KB, CLS 0, axe 0, hydration 0.

bash
git add -A
git commit

Commit (kanon): Media: Rubik next/font/local bilan, OG rasmlarda Rubik; LCP rasmiga preload; proxy matcher faqat slug'lar.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Build: Error while requesting resource … fonts.googleapis.com next/font/google + tarmoq yo'q next/font/local yoki tarmoqli build
TypeError: First argument to DataView constructor must be an ArrayBuffer OG shriftiga Uint8Array berildi .slice().buffer
OG rasmda shrift ishlamaydi woff2 berildi ttf/otf/woff
Shrift qo'llanmadi variable klassi <html> da yo'q className={font.variable}
next/font komponent ichida chaqirildi — xato Funksiya statik tahlil qilinadi Modul darajasida
Rus matni boshqa shriftda subsets da cyrillic yo'q Kerakli subset
worker strategiyasi ishlamaydi App Router'da hali yo'q lazyOnload

9. Mashqlar

Mashqlar kurs/mashqlar/23/32-next-font/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.

1-mashq (oson): strategiya tanlang

  • Google Analytics — strategy=""
  • Sayt pastidagi chat vidjeti — strategy=""
  • Sahifa ochilishidan oldin kerak bo'lgan bot himoyasi — strategy=""
Yechim
  • afterInteractive — sukut: sahifa jonlangach, iloji boricha erta; tashriflarni yo'qotmaydi.
  • lazyOnload — kutishi mumkin, brauzer bo'shaganda.
  • beforeInteractive — sahifa kodi uni kutishi kerak; faqat root layout'da.

2-mashq (o'rta): fayl imzosini tekshiring

Shrift fayli turini birinchi to'rt baytdan aniqlaydigan shriftTuri(baytlar) yozing: wOFF → "woff", wOF2 → "woff2", 00 01 00 00 → "ttf", OTTO → "otf", aks holda "noma'lum". DataView va getUint32 bilan o'qing. Keyin satori uchun yaroqliligini chiqaring (woff2 — yo'q).

Yechim
js
function shriftTuri(baytlar) {
  const dv = new DataView(baytlar.slice(0, 4).buffer);
  const imzo = dv.getUint32(0);
  if (imzo === 0x774f4646) return "woff";
  if (imzo === 0x774f4632) return "woff2";
  if (imzo === 0x00010000) return "ttf";
  if (imzo === 0x4f54544f) return "otf";
  return "noma'lum";
}

const namunalar = [
  [0x77, 0x4f, 0x46, 0x46],
  [0x77, 0x4f, 0x46, 0x32],
  [0x00, 0x01, 0x00, 0x00],
  [0x89, 0x50, 0x4e, 0x47],
];

for (const n of namunalar) {
  const tur = shriftTuri(new Uint8Array(n));
  const yaroqli = ["woff", "ttf", "otf"].includes(tur);
  console.log(`${tur}: satori ${yaroqli ? "o'qiydi" : "o'qimaydi"}`);
}

Konsolda:

text
woff: satori o'qiydi
woff2: satori o'qimaydi
ttf: satori o'qiydi
noma'lum: satori o'qimaydi

To'rtinchi namuna — PNG imzosi (\x89PNG): shrift emas. baytlar.slice(0, 4).buffer — darsdagi qoida: DataView ga faqat ArrayBuffer, va aynan kerakli baytlar bilan.

3-mashq (qiyin): zaxira shrift o'lchami

Next zaxira shrift uchun size-adjust ni ikki shriftning o'rtacha harf kengligidan hisoblaydi. Soddalashtirilgan model yozing: sizeAdjust(asosiyKenglik, zaxiraKenglik) = asosiy / zaxira × 100, ikki xona aniqlik bilan, % belgisi bilan. Keyin bitta qatorning kengligini hisoblang: 40 belgi × 9 px (zaxira) — tuzatishsiz va tuzatish bilan; asosiy shriftda 40 × 9.2376 px. Qaysi biri asosiyga yaqin? Yaxlitlash — toFixed.

Yechim
js
function sizeAdjust(asosiy, zaxira) {
  return `${((asosiy / zaxira) * 100).toFixed(2)}%`;
}

const zaxira = 9; // Arial, o'rtacha belgi kengligi (px)
const asosiy = 9.2376; // Rubik

const foiz = sizeAdjust(asosiy, zaxira);
console.log("size-adjust:", foiz);

const belgi = 40;
const tuzatishsiz = belgi * zaxira;
const tuzatilgan = belgi * zaxira * (parseFloat(foiz) / 100);
console.log("tuzatishsiz:", tuzatishsiz);
console.log("tuzatilgan:", tuzatilgan.toFixed(1));
console.log("asosiy:", (belgi * asosiy).toFixed(1));

Konsolda:

text
size-adjust: 102.64%
tuzatishsiz: 360
tuzatilgan: 369.5
asosiy: 369.5

Raqamlar ataylab tanlangan: natija — kanondagi haqiqiy size-adjust: 102.64%. Tuzatishsiz Arial qatori 9.5 px qisqa — shrift almashganda so'zlar keyingi qatorga o'tib, matn sakrardi. Next haqiqiy hisobda shrift metrikalari jadvalidan foydalanadi (capsize ma'lumotlari), bu esa g'oyaning modeli.

4-mashq: Portfolio qadami

Fontsource'dan Rubik'ning lotin variable woff2 faylini oling (va OFL.txt ni yoniga qo'ying), next/font/local bilan ulang. Build'dan keyin .next/static/chunks/*.css da Fallback qatorini toping. OG rasmlarga shrift qo'shing, /opengraph-image da sarlavha qalinligini tekshiring va holat 32 ni commit qiling.

Yechim

Kutilgan CSS — «Next nima yasadi» bo'limidagi to'rt qator (klass nomi va fayl xeshi boshqa bo'lishi mumkin). size-adjust qiymati shrift fayliga bog'liq: aynan shu Rubik faylida — 102.64%. OG uchun woff (400 va 700) alohida kerak — woff2 satori'da ishlamaydi. Agar DataView xatosi chiqsa — .slice().buffer ni unutgansiz.

10. Real ishda

  • Har Next loyihasida next/font — sukut tanlov; create-next-app shablonining o'zi Geist shriftini next/font/google bilan ulaydi.
  • Korporativ CI ko'pincha tashqi tarmoqqa cheklangan — shuning uchun katta jamoalar local shriftni afzal ko'radi.
  • GDPR va maxfiylik: 2022-yil 20-yanvarda Myunxen yer sudi (LG München I, ish 3 O 17493/20) qaror chiqardi. Sayt Google Fonts'ni Google serveridan ulagan edi — tashrifchining IP manzili roziliksiz Google'ga ketgan. Sud sayt egasiga tashrifchiga 100 yevro ma'naviy zarar to'lashni buyurdi. Sud muhim dalil sifatida aytdi: shriftni o'z serverdan berish mumkin edi. Shundan keyin Germaniyada bunday da'vo xatlari ko'paydi. next/font (local ham, google ham) bu muammoni hal qiladi — brauzer Google'ga bormaydi.
  • Intervyu savoli: "next/font CLS'ni qanday yo'qotadi?" — size-adjust va metrik override'lar bilan moslangan zaxira shrift.

Xulosa

  • next/font shriftni build'da loyihaga ko'chiradi, preload qiladi va size-adjust bilan moslangan zaxira shrift yasaydi — CLS 0.
  • local — repodagi fayl, internetsiz build; google — build vaqtida Google'dan, tarmoqsiz build yiqiladi (kanon tajribasi).
  • Rubik variable (300–900) bitta 35 KB faylda; har sahifaga +34.5 KB, JS o'zgarmadi.
  • OG (satori) — faqat ttf/otf/woff va ArrayBuffer: keshdan kelgan Uint8Array → .slice().buffer, aks holda DataView xatosi.
  • next/script: afterInteractive sukut, lazyOnload — kutishi mumkin bo'lganlar, beforeInteractive — faqat root layout'da.

Keyingi dars: Next.js'da stil va tema — Tailwind, CSS Modules va global CSS'ni o'lchov bilan solishtiramiz va loyiha kartasini CSS Module'ga o'tkazamiz.

Manbalar

  • Next.js hujjati (16.4.0, node_modules/next/dist/docs/): "Font Optimization", Font API reference (next/font/local, adjustFontFallback), ImageResponse, Script component (strategiyalar, worker ogohlantirishi), "Third Party Libraries" — nextjs.org/docs/app/api-reference/components/font (2026-10-21 da o'qildi)
  • Kanon natijalari: natijalar/tajriba/32-next-font-google.txt, natijalar/32-rasm-keyin.txt, natijalar/tekshiruv-32.txt; holat 32 (src/shriftlar/)
  • Next yasagan @font-face CSS va RSC preload ishorasi, Node Buffer hovuzi — biz ishga tushirdik: portfolio holat 32 nusxasi, next 16.4.0, Node 24.21.0, 2026-10-21
  • Fontsource Rubik 5.3.0 (SIL OFL 1.1) — fontsource.org/fonts/rubik
  • LG München I, 2022-01-20, Az. 3 O 17493/20 (Google Fonts, 100 €): IHK Bergische Region — ihk.de/bergische/recht-und-steuern/wettbewerbsrecht/google-fonts-5646176; Dr. Datenschutz — dr-datenschutz.de/schadensersatz-urteil-google-fonts-und-die-dsgvo/ (ikkalasi 2026-10-21 da ko'rildi)
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
next/font va next/script: o'z shriftingiz, zaxira shrift va 3-tomon skriptlar — IlmHamroh