Шрифты, статика и производительность

Подключаем шрифты без мерцания, кладём статику в public/ и разбираемся, что делает сайт быстрым.

next/font подключает и самохостит шрифты на этапе сборки, убирая внешний запрос и «мерцание» текста, а скорость сайта в целом измеряют метриками Core Web Vitals.

Шрифты через next/font

Если подключить шрифт ссылкой на Google Fonts, браузер делает запрос к стороннему домену, и пока шрифт грузится, текст мигает. next/font убирает и лишний запрос, и мерцание — шрифт скачивается при сборке и раздаётся с вашего домена:

// app/layout.tsx
import { Inter } from "next/font/google";

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

export default function RootLayout({ children }) {
  return (
    <html lang="ru" className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

Свой файл шрифта подключают через next/font/local — принцип тот же.

Статические ресурсы

Файлы из public/ отдаются от корня сайта. Туда кладут favicon, robots.txt и картинки, которые не нужно оптимизировать:

ФайлURL
public/robots.txt/robots.txt
public/og-image.png/og-image.png

Core Web Vitals

Скорость сайта измеряют тремя метриками Google:

МетрикаЧто измеряет
LCPВремя появления крупного контента
INPСкорость отклика на действия пользователя
CLSСтабильность вёрстки — насколько элементы «прыгают»

Многие оптимизации Next.js включены по умолчанию и улучшают эти метрики: серверные компоненты (меньше JS → лучше INP), SSG/ISR (готовый HTML → LCP), next/image (лёгкие картинки → LCP и CLS), next/font (нет мерцания → CLS).

Разделение кода

Next.js не отдаёт один гигантский бандл: код бьётся по маршрутам, и пользователь качает только нужное текущей странице. Прикинем выгоду:

const totalKb = 600;   // весь код приложения
const routes = 10;     // страниц
const perRoute = Math.round(totalKb / routes);

console.log("Без разделения грузим, КБ:", totalKb);
console.log("С разделением на страницу, КБ:", perRoute);

Вывод:

Без разделения грузим, КБ: 600
С разделением на страницу, КБ: 60

Тяжёлый клиентский компонент можно ещё и подгружать лениво через dynamic, чтобы он не утяжелял первый экран:

import dynamic from "next/dynamic";

const HeavyEditor = dynamic(() => import("./HeavyEditor"));

export default function Page() {
  return <HeavyEditor />;
}

Метрики смотрят в Lighthouse и в отчёте next build; правило — сначала измеряем, потом оптимизируем узкое место.

Итог

  • next/font самохостит шрифты (нет внешнего запроса и мерцания); статику кладут в public/.
  • Core Web Vitals (LCP, INP, CLS) — измеримая скорость; серверные компоненты, next/image и next/font улучшают их по умолчанию.
  • Код делится по маршрутам, тяжёлые куски грузят лениво через dynamic.
Проверьте себя
1. Какую проблему решает next/font?
AУменьшает размер изображений
BУбирает внешний запрос к шрифтовому сервису и мерцание текста при загрузке
CПереводит сайт на другой язык
DКэширует данные API
2. Куда кладут robots.txt, чтобы он был доступен по /robots.txt?
AВ app/
BВ public/
CВ next.config.js
DВ корень рядом с package.json
3. Что измеряют Core Web Vitals?
AРазмер исходного кода
BРеальную скорость и стабильность страницы (LCP, INP, CLS)
CКоличество строк CSS
DВерсию Node.js
4. Что делает next/dynamic при импорте компонента?
AДелает компонент серверным
BЛениво подгружает компонент, чтобы не утяжелять первый экран
CКэширует данные компонента
DЗапрещает рендер компонента
Поддержать проект