Почему 14 KB?

Вот в пример реальные запросы.

Вот сайт который влезает в 14кб:

А вот который не влезает:

Download - это и есть наш контент

1 ms против 63 ms.

Разница времени загрузки - 63 раза

Разница полезного веса - 7 раз

TCP Slow Start

В том то и ёбень, что TCP не отдаст контент одним пакетом. Даже когда сервер готов ответить, TCP говорит: “погоди братуха, у нас congestion control”: р Он начинает с initcwnd - 10 сегментов (RFC 6928) - это 1460байт.

  • Сервер послал 14 KB - ждёт ACK,
  • Пришёл ACK - окно удвоилось до 20 сегментов (~29кб),
  • Послал теперь 29KB - снова ждёт…

И так пока не передаст всё.

Каждый луп - это RTT.

Чем больше ответ - тем больше rounds.

Если ответ влазит в 14.6 KB - он улетает одним пакетом.

Без ожидания && без удвоения && без лишних RTT.

:: One round trip.

На больших файлах (картинки и прочий тяжелый контент) эта особенность уже не доставляет проблем, т.к. tcp успевает разогнаться.

Но в бол-ве случаев на сайтах файлы меньше 100кб - и это уже реальная проблема.

И это при условии что у тебя всего один запрос. А если отдельно шрифты, скрипты, картинки - каждый из них проходит полный круг заново. Со своим setup, своим slow start, своими RTT. Один сайт превращается в 5-10-30 последовательных запросов, и каждый жрёт время на общение протоколов, а не передачу полезных данных.

В качестве плохого примера - сайт New-York Times - 891 http запрос на 9мб контента, 6 секунд blocking time, хотя сайт - буквально стандартный газетный layout, где ничего тяжелого быть не может.

Клубы

Есть 14KB Club - сайты до 14 KB сырыми. Там считают uncompressed size, т.е. по сути туда не пустят сайт, что весит условные 20-30кб, но благодаря сжатию gzip может уместиться в 1rtt - спорный момент правил.

512KB Club - не влезать сюда - ебейшее неуважение к пользователям и к интернету в целом. Удаляйте свой сайт нахуй.

данный бугурт не относится к полезной информации на сайте, по типу фото-видео


Мои потуги

Есть у меня сайтец sccl.cc.

Запилен на Zine - SSG на Zig. Три страницы: contacts, projects, peripherals.

Исходно сервер отдавал:

  • HTML (~15kb)
  • Space Mono 400 woff2 (~40kb)
  • Аватарка png (~2mb)
  • Фавикон png (~1mb)

на скрине уже немного заоптемайзенный, было хуже :skull:

(до переезда на zine был ваще 150+кб, см Migration-from-Astro-to-Zine.md)

Четыре запроса на страницу, на контент, который суммарно нихрена не весит.

Всё это с учётом что полный setup (DNS + TCP + TLS) происходит один раз (keep-alive, HTTP/2). Но даже так - на каждую вкладку, на каждый переход с другой страницы - новый setup. А шрифт и аватарка висят отдельными запросами.

Оптимизация

План: всё в один HTML. Base64 инлайн всего, ноль внешних запросов. И чтоб влезало в initcwnd.

Шрифт

Самый жирный момент - у меня было 2 шрифта и жирные версии к ним.

Было решено выкинуть всё, кроме одного.

а из файла шрифта выкинуть всё кроме ASCII символов, которые реально юзаются на сайте.

Отключить хинтинг, отключить layout features.

Итог: 4.2кб. Потом base64 в @font-face 5.7кб текста в HTML.

Это единственная уступка эстетике. Лучше конечно вообще без кастом шрифтов.

Аватарка

Инишиал был ультра жирныч.

Но шаклозатором кортинка сначал была ужата до трёх цвета.

И в PNG весела 1.9kb.

При переконверте в WebP: стало 702 b. Base64 → 940 B.

Фавиконка

199b, осталась в png.

268b в base64.

JS

По хорошему тут можно было прям люто резать, но у меня удалось сохранить весь функционал на сайте и пихнуть весь js inline. У меня там и анимированные кнопки, анимированный фон и пасхалска с анимацией - крч всё лишнее говно, без которого можно было бы хоть в 5кб сайт ужимать. (что не дало бы скорости)

Итог

До: 4 запроса, ~50kb суммарно

После: 1 запрос, 12kb gzip / 27kb raw

Влезает в initcwnd. Один TCP-пакет. Один round trip на данные.

Дилемма

Инлайн всего - это компромисс.

При переходе на другую страницу браузер качает тот же шрифт по новой - шрифт внутри HTML, он не кешируется отдельно. С отдельным файлом шрифт закешировался бы после первого раза, и вторую страницу качал бы без него.

Так же стоит учитывать что инлайн обычно весит чуть больше чем внешняя зависимость, и если мы и так не лезем в initcwnd - то и инлайн нам ненужен.

Пример

1. Всё в одном HTML (base64 шрифты)

  • 2 страницы по 14кб каждая
  • каждая грузится за 1 round trip
  • но каждый раз жрёшь полные 14кб, даже если шрифт повторяется

2. HTML + отдельный шрифт

  • 2 страницы по 8кб + шрифт 4кб отдельно
  • первый заход: 2 запроса (HTML + шрифт)
  • переход между страницами: только 8кб (шрифт закеширован)

В реальном интернете разницы между скоростью загрузки 14кб и 8кб - не почувствовать.

А делеи между пакетами - да.