\n\n\n\n\n\n\n```\n\n**Разделите JavaScript на бандлы (Code Splitting):**\n\n```javascript\n// webpack.config.js или vite.config.js\nconst config = {\n entry: './src/index.js',\n output: {\n filename: '[name].[contenthash].js',\n chunkFilename: '[name].[contenthash].js'\n },\n optimization: {\n splitChunks: {\n chunks: 'all',\n cacheGroups: {\n vendor: {\n test: /[\\\\/]node_modules[\\\\/]/,\n name: 'vendors',\n priority: 10\n },\n common: {\n minChunks: 2,\n priority: 5,\n reuseExistingChunk: true\n }\n }\n }\n }\n};\n```\n\n**Ленивая загрузка компонентов (React):**\n\n```javascript\nimport { lazy, Suspense } from 'react';\n\n// Загружается только при необходимости\nconst HeavyComponent = lazy(() => import('./HeavyComponent'));\n\nfunction App() {\n return (\n Загрузка...
}>\n \n \n );\n}\n```\n\n### 4. Оптимизация изображений\n\n**Используйте современные форматы:**\n\n```html\n\n\"Фото\"\n\n\n\n \n \n \"Фото\"\n\n```\n\n**Оптимизируйте размер изображений:**\n\n```bash\n# Используйте imagemin\nnpm install -D imagemin imagemin-mozjpeg imagemin-pngquant\n```\n\n**Ленивая загрузка изображений:**\n\n```html\n\n\"Изображение\"\n\n\n\"Изображение\"\n```\n\n**Используйте CDN для изображений:**\n\n```html\n\n\"Изображение\"\n```\n\n### 5. Оптимизация шрифтов\n\n**Загружайте шрифты асинхронно:**\n\n```html\n\n\n\n\n\n\n\n```\n\n**Используйте font-display: swap:**\n\n```css\n@font-face {\n font-family: 'Inter';\n src: url('/fonts/inter.woff2') format('woff2');\n font-display: swap; /* Показать fallback шрифт сразу, затем заменить */\n}\n```\n\n### 6. Кеширование\n\n**Используйте HTTP кеш:**\n\n```javascript\n// На сервере (Node.js/Express)\napp.use((req, res, next) => {\n // Кешируем статичные файлы на 1 год\n if (req.url.startsWith('/static/')) {\n res.set('Cache-Control', 'public, max-age=31536000, immutable');\n }\n // HTML кешируем на 1 час\n else if (req.url === '/' || req.url.endsWith('.html')) {\n res.set('Cache-Control', 'public, max-age=3600');\n }\n next();\n});\n```\n\n**Service Worker для кеширования:**\n\n```javascript\n// service-worker.js\nself.addEventListener('install', (event) => {\n event.waitUntil(\n caches.open('v1').then((cache) => {\n return cache.addAll([\n '/',\n '/styles.css',\n '/app.js',\n '/offline.html'\n ]);\n })\n );\n});\n\nself.addEventListener('fetch', (event) => {\n event.respondWith(\n caches.match(event.request).then((response) => {\n return response || fetch(event.request);\n })\n );\n});\n```\n\n### 7. Оптимизация сервера\n\n**Используйте CDN:**\n\n```\nПользователь в Москве → Cloudflare CDN (Москва) → быстрее\nВместо:\nПользователь в Москве → Сервер в США → медленнее\n```\n\n**Сжатие контента (gzip/brotli):**\n\n```javascript\n// Node.js\nconst compression = require('compression');\napp.use(compression()); // Включить gzip\n```\n\n**HTTP/2 Server Push:**\n\n```javascript\n// Отправить критичные ресурсы до того как браузер их запросит\nres.setHeader('Link', '; rel=preload; as=style');\n```\n\n### 8. Инструменты измерения\n\n**Используйте Core Web Vitals:**\n\n```javascript\n// Измеряем метрики\nweb-vital library:\n\nimport { getCLS, getFID, getFCP, getLCP } from 'web-vitals';\n\ngetFCP((metric) => console.log('FCP:', metric.value));\ngetLCP((metric) => console.log('LCP:', metric.value));\ngetCLS((metric) => console.log('CLS:', metric.value));\n```\n\n**Используйте Lighthouse:**\n\n```bash\n# Анализируем производительность\nnpm install -g lighthouse\nlighthouse https://example.com --view\n```\n\n## Чеклист оптимизации\n\n```\n1. HTML\n ✓ Минимизирован\n ✓ Критичный CSS в head\n ✓ Правильный порядок скриптов\n\n2. CSS\n ✓ Удалены неиспользуемые стили\n ✓ Минимизирован\n ✓ Загружается асинхронно где возможно\n\n3. JavaScript\n ✓ Удалены неиспользуемые зависимости\n ✓ Code splitting реализован\n ✓ async/defer используется правильно\n ✓ Минимизирован\n\n4. Изображения\n ✓ Оптимизированы (WebP, размер)\n ✓ Ленивая загрузка где нужна\n ✓ Используется CDN\n\n5. Шрифты\n ✓ Асинхронная загрузка\n ✓ font-display: swap\n ✓ Ограничено количество шрифтов\n\n6. Сервер\n ✓ Используется CDN\n ✓ Включен gzip/brotli\n ✓ Правильные Cache-Control headers\n\n7. Тестирование\n ✓ Lighthouse score > 90\n ✓ FCP < 1.8 сек\n ✓ LCP < 2.5 сек\n```\n\n## Практический пример: Оптимизация Next.js приложения\n\n```javascript\n// next.config.js\nmodule.exports = {\n compress: true, // Gzip\n swcMinify: true, // Минификация\n images: {\n formats: ['image/avif', 'image/webp'], // Современные форматы\n deviceSizes: [640, 750, 828, 1080, 1200, 1920],\n imageSizes: [16, 32, 48, 64, 96, 128, 256]\n },\n productionBrowserSourceMaps: false, // Не загружать sourcemaps\n experimental: {\n optimizePackageImports: ['lodash'] // Оптимизировать импорты\n }\n};\n\n// pages/index.tsx\nimport Image from 'next/image';\nimport dynamic from 'next/dynamic';\n\n// Ленивая загрузка\nconst HeavyChart = dynamic(() => import('@/components/Chart'), {\n loading: () =>
Загрузка...
,\n ssr: false\n});\n\nexport default function Home() {\n return (\n <>\n \n \n \n );\n}\n```\n\n## Выводы\n\nЧтобы уменьшить время до первой отрисовки: оптимизируйте HTML (минимизация, критичный CSS), CSS (удалите неиспользуемое, асинхронная загрузка), JavaScript (code splitting, async/defer, lazy loading), изображения (WebP, CDN, lazy loading), шрифты (async, font-display: swap), используйте CDN и кеширование. Тестируйте с помощью Lighthouse и Core Web Vitals. Идеальная FCP должна быть менее 1.8 секунд, LCP менее 2.5 секунд.","dateCreated":"2026-04-03T11:44:13.217519","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Как можно уменьшить время до первой отрисовки страницы?

1.0 Junior🔥 131 комментариев
#Оптимизация и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое время до первой отрисовки

Первая отрисовка страницы (First Contentful Paint - FCP) - это момент, когда браузер отрисовывает первый контент на экране. Это критический метрик для пользовательского опыта: более быстрая загрузка = лучше. Google говорит, что идеальное время - менее 1.8 секунд.

Процесс загрузки и отрисовки страницы

1. Пользователь вводит URL в адресную строку
2. Браузер отправляет запрос на сервер (DNS + TCP + SSL)
3. Сервер отправляет HTML
4. Браузер начинает парсить HTML
5. Браузер загружает CSS (блокирует рендеринг)
6. Браузер выполняет JavaScript (может блокировать парсинг)
7. Браузер строит DOM и CSSOM
8. Браузер создает Render Tree
9. ПЕРВАЯ ОТРИСОВКА (FCP) - видно первый контент
10. Браузер загружает изображения и шрифты
11. JavaScript обновляет страницу
12. Браузер отрисовывает финальную версию (LCP)

Способы уменьшить время до FCP

1. Оптимизация HTML

Минимизируйте HTML файл:

<!-- ❌ Много пробелов и комментариев -->
<html>
  <head>
    <!-- Это комментарий -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

<!-- ✅ Минимизировано (автоматически при продакшене) -->
<html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width"></head><body><div id="app"></div></body></html>

Поместите критичный CSS в head:

<!DOCTYPE html>
<html>
<head>
  <!-- Критичные стили для Above The Fold -->
  <style>
    body { margin: 0; font-family: -apple-system, sans-serif; }
    .header { background: #f5f5f5; padding: 1rem; }
  </style>
  
  <!-- Остальной CSS загружается асинхронно -->
  <link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'">
</head>
<body>
  <header class="header">Контент выше сгиба</header>
  <main id="app"></main>
</body>
</html>

2. Оптимизация CSS

Подгружайте CSS асинхронно:

<!-- ❌ Блокирует рендеринг -->
<link rel="stylesheet" href="all.css">

<!-- ✅ Загружается асинхронно -->
<link rel="stylesheet" href="all.css" media="print" onload="this.media='all'">

<!-- ✅ Или используйте preload -->
<link rel="preload" href="all.css" as="style">
<link rel="stylesheet" href="all.css">

Удалите неиспользуемый CSS:

# Используйте PurgeCSS или Tailwind для удаления неиспользуемых стилей
npm install -D purgecss
// purgecss.config.js
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}'],
  css: ['./src/styles.css'],
  output: './dist/styles.min.css'
};

Минимизируйте CSS:

/* До минификации */
body {
  margin: 0;
  padding: 0;
  font-family: 'Inter', sans-serif;
  background-color: #ffffff;
}

/* После минификации (выполняется автоматически в продакшене) */
body{margin:0;padding:0;font-family:'Inter',sans-serif;background-color:#fff}

3. Оптимизация JavaScript

Отложите загрузку JavaScript:

<!-- ❌ Блокирует парсинг HTML -->
<script src="app.js"></script>

<!-- ✅ Загружается асинхронно -->
<script src="app.js" async></script>

<!-- ✅ Загружается после парсинга HTML (для Non-critical JS) -->
<script src="analytics.js" defer></script>

Разделите JavaScript на бандлы (Code Splitting):

// webpack.config.js или vite.config.js
const config = {
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].js'
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10
        },
        common: {
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true
        }
      }
    }
  }
};

Ленивая загрузка компонентов (React):

import { lazy, Suspense } from 'react';

// Загружается только при необходимости
const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Загрузка...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

4. Оптимизация изображений

Используйте современные форматы:

<!-- ❌ Старый способ -->
<img src="photo.jpg" alt="Фото">

<!-- ✅ Современный способ с WebP -->
<picture>
  <source srcset="photo.webp" type="image/webp">
  <source srcset="photo.jpg" type="image/jpeg">
  <img src="photo.jpg" alt="Фото">
</picture>

Оптимизируйте размер изображений:

# Используйте imagemin
npm install -D imagemin imagemin-mozjpeg imagemin-pngquant

Ленивая загрузка изображений:

<!-- ❌ Загружается всегда -->
<img src="image.jpg" alt="Изображение">

<!-- ✅ Загружается только при видимости -->
<img src="placeholder.jpg" data-src="image.jpg" alt="Изображение" loading="lazy">

Используйте CDN для изображений:

<!-- Cloudinary, Imgix, или другой CDN -->
<img src="https://cdn.example.com/image.jpg?w=800&q=80" alt="Изображение">

5. Оптимизация шрифтов

Загружайте шрифты асинхронно:

<!-- ❌ Блокирует рендеринг -->
<link href="https://fonts.googleapis.com/css2?family=Inter" rel="stylesheet">

<!-- ✅ Асинхронная загрузка с fallback -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preload" href="https://fonts.gstatic.com/s/inter/..." as="font" type="font/woff2" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter" rel="stylesheet" media="print" onload="this.media='all'">

Используйте font-display: swap:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap; /* Показать fallback шрифт сразу, затем заменить */
}

6. Кеширование

Используйте HTTP кеш:

// На сервере (Node.js/Express)
app.use((req, res, next) => {
  // Кешируем статичные файлы на 1 год
  if (req.url.startsWith('/static/')) {
    res.set('Cache-Control', 'public, max-age=31536000, immutable');
  }
  // HTML кешируем на 1 час
  else if (req.url === '/' || req.url.endsWith('.html')) {
    res.set('Cache-Control', 'public, max-age=3600');
  }
  next();
});

Service Worker для кеширования:

// service-worker.js
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('v1').then((cache) => {
      return cache.addAll([
        '/',
        '/styles.css',
        '/app.js',
        '/offline.html'
      ]);
    })
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

7. Оптимизация сервера

Используйте CDN:

Пользователь в Москве → Cloudflare CDN (Москва) → быстрее
Вместо:
Пользователь в Москве → Сервер в США → медленнее

Сжатие контента (gzip/brotli):

// Node.js
const compression = require('compression');
app.use(compression()); // Включить gzip

HTTP/2 Server Push:

// Отправить критичные ресурсы до того как браузер их запросит
res.setHeader('Link', '</styles.css>; rel=preload; as=style');

8. Инструменты измерения

Используйте Core Web Vitals:

// Измеряем метрики
web-vital library:

import { getCLS, getFID, getFCP, getLCP } from 'web-vitals';

getFCP((metric) => console.log('FCP:', metric.value));
getLCP((metric) => console.log('LCP:', metric.value));
getCLS((metric) => console.log('CLS:', metric.value));

Используйте Lighthouse:

# Анализируем производительность
npm install -g lighthouse
lighthouse https://example.com --view

Чеклист оптимизации

1. HTML
  ✓ Минимизирован
  ✓ Критичный CSS в head
  ✓ Правильный порядок скриптов

2. CSS
  ✓ Удалены неиспользуемые стили
  ✓ Минимизирован
  ✓ Загружается асинхронно где возможно

3. JavaScript
  ✓ Удалены неиспользуемые зависимости
  ✓ Code splitting реализован
  ✓ async/defer используется правильно
  ✓ Минимизирован

4. Изображения
  ✓ Оптимизированы (WebP, размер)
  ✓ Ленивая загрузка где нужна
  ✓ Используется CDN

5. Шрифты
  ✓ Асинхронная загрузка
  ✓ font-display: swap
  ✓ Ограничено количество шрифтов

6. Сервер
  ✓ Используется CDN
  ✓ Включен gzip/brotli
  ✓ Правильные Cache-Control headers

7. Тестирование
  ✓ Lighthouse score > 90
  ✓ FCP < 1.8 сек
  ✓ LCP < 2.5 сек

Практический пример: Оптимизация Next.js приложения

// next.config.js
module.exports = {
  compress: true, // Gzip
  swcMinify: true, // Минификация
  images: {
    formats: ['image/avif', 'image/webp'], // Современные форматы
    deviceSizes: [640, 750, 828, 1080, 1200, 1920],
    imageSizes: [16, 32, 48, 64, 96, 128, 256]
  },
  productionBrowserSourceMaps: false, // Не загружать sourcemaps
  experimental: {
    optimizePackageImports: ['lodash'] // Оптимизировать импорты
  }
};

// pages/index.tsx
import Image from 'next/image';
import dynamic from 'next/dynamic';

// Ленивая загрузка
const HeavyChart = dynamic(() => import('@/components/Chart'), {
  loading: () => <div>Загрузка...</div>,
  ssr: false
});

export default function Home() {
  return (
    <>
      <Image
        src="/hero.jpg"
        width={1200}
        height={600}
        priority // Высокий приоритет для LCP
        sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
      />
      <HeavyChart />
    </>
  );
}

Выводы

Чтобы уменьшить время до первой отрисовки: оптимизируйте HTML (минимизация, критичный CSS), CSS (удалите неиспользуемое, асинхронная загрузка), JavaScript (code splitting, async/defer, lazy loading), изображения (WebP, CDN, lazy loading), шрифты (async, font-display: swap), используйте CDN и кеширование. Тестируйте с помощью Lighthouse и Core Web Vitals. Идеальная FCP должна быть менее 1.8 секунд, LCP менее 2.5 секунд.

Как можно уменьшить время до первой отрисовки страницы? | PrepBro