Перейти к основному содержимому

Ресурсы

Ресурсы — изображения, шрифты, скрипты — напрямую влияют на LCP и CLS. Правильная стратегия загрузки, форматы и resource hints ускоряют первый экран без изменений в логике приложения.


Изображения

MUST

  • Современные форматы — WebP или AVIF с fallback на JPEG/PNG.
  • Retina — размер ресурса не превышает 2x от отображаемого размера.
  • Адаптивность — обязательно использовать атрибуты srcset / sizes.
  • LCP-изображениеfetchpriority="high", запрещён loading="lazy".
  • Lazy loading — для изображений below the fold; место резервируется для предотвращения CLS.
  • Явные размерыwidth и height обязательны, либо aspect-ratio для защиты от CLS.

FORBIDDEN

  • loading="lazy" для изображений первого экрана (LCP).
  • Изображения без указания размеров — приводит к layout shift (CLS).

Next.js — next/image

// ✅ LCP-изображение — priority, без lazy
import Image from 'next/image';

export function Hero() {
return (
<Image
src="/hero.avif"
alt="Product hero"
width={1200}
height={640}
priority // fetchpriority="high", без lazy
/>
);
}

// ✅ Изображение below the fold — lazy по умолчанию
<Image src="/product.webp" alt="Product" width={400} height={300} />;

Astro — astro:assets

---
import { Image } from 'astro:assets';
import hero from '../assets/hero.jpg';
---

<Image src={hero} alt="Product hero" width={1200} height={640} format="webp" />

Шрифты

MUST

  • Формат — WOFF2 — единственный современный формат.
  • Хостинг — локальный, не через Google CDN: устраняет лишнее сетевое соединение, независимость от внешней инфраструктуры, соответствие GDPR.
  • font-display: swap — текст виден сразу, шрифт подменяется после загрузки.
  • Subsetting — загружать только нужные глифы (latin, cyrillic и т.д.).

Инструменты для подготовки шрифтов

Next.js — next/font

// app/layout.tsx
// next/font автоматически делает subsetting и self-hosting
import { Inter } from 'next/font/google';

const inter = Inter({
subsets: ['latin', 'cyrillic'],
display: 'swap',
});

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html className={inter.className}>
<body>{children}</body>
</html>
);
}

Resource Hints

SHOULD

  • preload — критичные ресурсы текущей страницы: шрифты, LCP-изображение.
  • prefetch — ресурсы вероятных следующих навигаций (обычно управляется фреймворком).
  • preconnect — раннее соединение с критическими внешними доменами (API, CDN).

FORBIDDEN

  • Использовать hints без измеримого эффекта — избыточный preload мешает браузеру расставлять приоритеты.

Next.js — Pages Router

// pages/_document.tsx
export default function Document() {
return (
<Html>
<Head>
<link rel="preconnect" href="https://api.example.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin=""
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}

Next.js — App Router

// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html>
<head>
<link rel="preconnect" href="https://api.example.com" />
</head>
<body>{children}</body>
</html>
);
}

Сжатие и передача данных

MUST

  • Все текстовые ресурсы сжимаются: Brotli (предпочтительно) или Gzip.
  • Протоколы: HTTP/2 или HTTP/3 обязательно.

HTTP-кэширование

MUST

Тип ресурсаCache-Control
Статические ресурсы (JS, CSS, шрифты, изображения)public, max-age=31536000, immutable
Редко меняющиеся данные (справочники, конфигурации)public, max-age=3600, stale-while-revalidate=86400
Часто меняющиеся данныеno-cache или короткий max-age
Персональные данныеprivate, no-store

Стратегия кэширования API-ответов согласовывается с backend-командой и настраивается на стороне backend / CDN.


CSS-in-JS

SHOULD

Предпочитать zero-runtime решения — они не генерируют стили в runtime и не вставляют их в DOM:

  • CSS Modules
  • Tailwind
  • Vanilla Extract

Runtime CSS-in-JS (styled-components, Emotion) добавляют overhead: стили генерируются в runtime и вставляются в DOM на каждый рендер.


Third-party скрипты

MUST

  • Указывать атрибуты async / defer для сторонних скриптов.
  • В Next.js — подключать через next/script со стратегиями lazyOnLoad или afterInteractive.
import Script from 'next/script';

// ✅ Загружается после интерактивности страницы
<Script src="https://analytics.example.com/script.js" strategy="afterInteractive" />

// ✅ Загружается в фоне когда браузер свободен
<Script src="https://widget.example.com/widget.js" strategy="lazyOnLoad" />