11 способов оптимизации веб-сайта
Вы потратили недели напряженной работы на создание своего сайта, и теперь он наконец готов к запуску! Однако для того, чтобы ваш сайт работал наилучшим образом, необходимо позаботиться о некоторых моментах. В этой статье мы рассмотрим различные способы оптимизации сайта для повышения удобства пользователей и ускорения загрузки, что приведет к повышению рейтинга в поисковых системах.
Когда браузер запрашивает веб-страницу, он сначала получает HTML-документ. Браузер разбирает этот документ, и если в нем встречается внешний файл, то браузер посылает еще один запрос на его получение. Например, представьте, что у вас есть сайт со следующей структурой:
.
├── index.html
├── package.json
└── statics
├── css
│ ├── footer.css
│ ├── header.css
│ └── main.css
├── images
│ ├── 1.jpg
│ ├── 2.jpg
│ ├── 3.png
│ ├── 4.png
│ └── 5.jpg
└── js
├── foo.js
├── bar.js
└── index.js
Чтобы отобразить файл index.html
, браузеру придется выполнить в общей сложности 12 запросов, включая 1 HTML-файл, 3 CSS-файла, 3 JavaScript-файла и 5 изображений. Этот процесс потребует большого количества времени и ресурсов, что приведет к снижению производительности сайта.
Оптимизируйте изображения
К счастью, существуют некоторые способы повышения скорости загрузки сайта, такие как объединение и минимизация статических файлов, оптимизация изображений, кэширование ресурсов и многие другие. Все эти приемы мы рассмотрим в данной статье. Но давайте начнем с изображений.
Используйте современные форматы веб-изображений
Начнем с того, что изображения на этом сайте представлены в формате JPG или PNG, которые, как правило, имеют больший размер файлов и низкую производительность по сравнению с современными форматами, такими как WebP и AVIF.
Существует множество "облачных" инструментов и сайтов, позволяющих конвертировать изображения, но проблема с ними заключается в том, что для обработки файлов их обычно приходится загружать, а некоторые из них не являются бесплатными. В этой статье я хочу представить программу FFmpeg, которая позволяет конвертировать изображения локально с помощью одной простой команды.
Если вы используете Mac, вы можете установить FFmpeg с помощью Homebrew:
brew install ffmpeg
Если вы используете Windows, используйте программу Winget:
winget install --id=Gyan.FFmpeg -e
В качестве альтернативы можно просто загрузить программу установки с официального сайта FFmpeg.
После завершения процесса установки откройте терминал и перейдите в каталог с изображениями.
cd /path/to/images
Затем преобразуйте изображения с помощью следующей команды:
for file in *.{jpg,png}; do ffmpeg -i "$file" -c:v libwebp -q:v 80 "$(basename "$file" .${file##*.}).webp"; done
Если вы используете Windows (CMD), выполните эту команду:
for %i in (*.jpg *.png) do ffmpeg -i "%i" -c:v libwebp -q:v 80 "%~ni.webp"
В случае PowerShell:
Get-ChildItem -Path . | Where-Object { $_.Extension -match '\.jpg$|\.png$' } | ForEach-Object { ffmpeg -i $_.FullName -c:v libwebp -q:v 80 ($_.BaseName + ".webp") }
Конечно, возможно, придется изменить эту команду в соответствии с конкретными условиями:
{jpg,png}
перечисляет все форматы изображений в каталоге.-c:v libwebp
определяет кодек, используемый для WebP. Не стоит изменять этот параметр, если вы не знаете, что делаете.-q:v 80
задает уровень сжатия изображений. При необходимости можно настроить значение в диапазоне от0
(наименьшее качество, наибольшее сжатие) до100
(наибольшее качество, без сжатия).
Со степенью сжатия можно поиграть, но, по моему опыту, можно установить значение не более 20 без особого ущерба для качества изображения. Вот сравнение.
FFmpeg - это очень мощный мультимедийный инструмент, способный решать широкий спектр задач, связанных с обработкой аудио, изображений и видео. На основе FFmpeg работают многие известные сайты и инструменты, такие как YouTube, Twitch, VLC Media Player и т.д. Более подробная информация приведена в официальной документации.
Разные изображения для разных экранов просмотра
В большинстве случаев ваш сайт создается для устройств с различными размерами экрана. Для маленького экрана обычно лучше использовать изображения меньшего размера, а для больших экранов - большого. В идеале можно создавать различные версии одного и того же изображения с помощью FFmpeg, а затем встраивать их с помощью элемента <picture>
вместо <img>
.
Элемент <picture>
позволяет определить несколько источников для одного и того же изображения, а затем браузер может выбирать различные источники в зависимости от размера области просмотра.
<picture>
<source media="(max-width: 600px)" srcset="small.webp">
<source media="(max-width: 1200px)" srcset="medium.webp">
<img src="large.webp" alt="example image">
</picture>
В данном примере браузер отобразит файл small.webp
на маленьком экране (<600px
), файл medium.webp
на среднем экране (600px-1200px
) и файл large.webp
на большом экране (>1200px
).
Ленивая загрузка изображений
Наконец, следует также не загружать изображения, если они не нужны сразу.
<picture>
<source media="(max-width: 600px)" srcset="small.webp">
<source media="(max-width: 1200px)" srcset="medium.webp">
<img src="large.webp" alt="example image" loading="lazy">
</picture>
Это гарантирует, что браузер получит изображение только тогда, когда пользователь прокрутит страницу вниз до его местоположения. Однако если изображение необходимо для корректного отображения веб-страницы при первоначальной загрузке, то лучше всего установить значение load
в eager
, что позволит браузеру получить его как можно быстрее.
<picture>
<source media="(max-width: 600px)" srcset="small.webp">
<source media="(max-width: 1200px)" srcset="medium.webp">
<img src="large.webp" alt="example image" loading="eager">
</picture>
Оптимизация файлов CSS и JavaScript
Во-вторых, обратите внимание, что в данном проекте имеется 3 CSS-файла и 3 JavaScript-файла. Лучше всего разделять код на различные модули на этапе разработки для более эффективного управления файлами, однако в производственной среде вы захотите, чтобы ваша веб-страница загружала как можно меньше внешних файлов для улучшения качества работы пользователей. И эти файлы должны быть как можно меньше.
Объединение и минимизация CSS-файлов
Для этого существует множество фронтенд-инструментов. Например, PostCSS - популярный CSS-процессор, позволяющий объединять и минимизировать код. При наличии подходящего плагина он может даже исправлять код с учетом проблем совместимости, обеспечивая работу стилей CSS во всех браузерах.
PostCSS встроен в веб-пакеты, о которых мы поговорим позже. Однако если вы хотите использовать PostCSS самостоятельно, его можно установить в свой проект с помощью следующей команды npm
:
npm install postcss postcss-cli postcss-import postcss-preset-env cssnano --save-dev
Создайте файл конфигурации postcss.config.js
в корневом каталоге проекта. Конфигурация должна включать все необходимые плагины.
module.exports = {
plugins: [
require("postcss-import"),
require("postcss-preset-env"),
require("cssnano"),
],
};
Создайте входной CSS-файл. Этот входной файл должен импортировать все остальные необходимые CSS-файлы.
.
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
└── statics
├── css
│ ├── footer.css
│ ├── header.css
│ ├── main.css
│ └── styles.css
├── images
└── js
styles.css
@import "./header.css";
@import "./main.css";
@import "./footer.css";
Объедините и сверните файл с помощью следующей команды:
npx postcss statics/css/styles.css -o dist/styles.css
А в HTML-документ достаточно импортировать только выходной файл dist/styles.css
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="dist/styles.css">
</head>
<body>
. . .
</body>
</html>
В качестве альтернативы можно разделить критический и некритический CSS, загрузить критический CSS в раздел head
, а некритический CSS - в конец раздела body
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="dist/critical.css">
</head>
<body>
. . .
<link rel="stylesheet" href="dist/non-critical.css">
</body>
</html>
Использование веб-пакетов
В настоящее время сложность веб-приложений растет в геометрической прогрессии. Нельзя полагаться на базовый CSS-процессор, чтобы оптимизировать и управлять всем. Для решения этой проблемы созданы веб-пакеты. Они предназначены для обработки CSS, JavaScript, а также изображений, позволяя управлять всеми статическими активами в одном месте.
Webpack - один из самых популярных вариантов, имеющий 63,6 тыс. звезд на GitHub. Он упаковывает модули (JavaScript, CSS, изображения и т.д.) в пакетированные активы, которые могут быть запущены браузером. В демонстрационных целях вот как можно установить Webpack в свой проект:
npm install webpack webpack-cli --save-dev
Предположим, что у вас есть следующая структура проекта:
.
├── dist
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── statics
│ ├── css
│ ├── images
│ └── js
│ ├── bar.js
│ ├── foo.js
│ └── index.js
└── webpack.config.js
foo.js
export default function foo() {
console.log("foo");
}
bar.js
export default function bar() {
console.log("bar");
}
index.js
import foo from "./foo.js";
import bar from "./bar.js";
foo();
bar();
console.log("Hello, World!");
В данном случае index.js
является точкой входа в проект. Создайте конфигурационный файл (webpack.config.js
) в корневом каталоге проекта и убедитесь, что параметр entry
указывает на файл index.js
.
const path = require("path");
module.exports = {
entry: "./statics/js/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
};
Далее можно запустить Webpack с помощью следующей команды:
npx webpack --config webpack.config.js
Будет сгенерирован файл bundle.js
, содержащий свернутую версию всего JavaScript-кода.
(()=>{"use strict";console.log("foo"),console.log("bar"),console.log("Hello, World!")})();
По умолчанию Webpack работает только с файлами JavaScript, но вы можете расширить его возможности, установив различные загрузчики. Например, css-загрузчик позволяет Webpack обрабатывать CSS-файлы, а postcss-загрузчик делает его совместимым с процессором PostCSS, о котором мы только что говорили. Более подробную информацию можно найти на страницах, на которые даны ссылки.
Помимо Webpack, существует множество других популярных веб-бандлеров, таких как Parcel, Esbuild, Rollup и др. Все они обладают своими уникальными возможностями и достоинствами, и выбор следует делать, исходя из потребностей и требований конкретного проекта. Более подробную информацию можно найти на их официальных сайтах.
Говоря о фронтенд-инструментах, нельзя не упомянуть о Vite. По мере роста сложности приложения нередки случаи, когда одно приложение содержит сотни и даже тысячи модулей. В результате веб-компоновщикам часто требуется неоправданно много времени, чтобы обработать их все, прежде чем можно будет запустить dev-сервер.
Vite призван решить эту проблему, обеспечив встроенную поддержку технологии горячей замены модулей (HMR), которая позволяет разработчикам применять обновления кода в режиме реального времени без необходимости обновлять всю страницу. Уникальный подход используется и при компоновке активов. Вместо того чтобы собирать все вместе, компания создает небольшие пакеты для каждого отдельного модуля, а затем по мере необходимости передает их браузеру. Такой подход позволяет Vite ускорить процесс сборки и загрузки. Если вы ищете быстрый и надежный инструмент для сборки фронтенда, обязательно попробуйте Vite.
Асинхронный режим vs Отложенный режим
В настоящее время файлы JavaScript становятся все более сложными. Они часто тяжелее HTML-документа, и их загрузка и обработка занимает больше времени, даже если они объединены и свернуты.
По умолчанию браузер разбирает HTML-файл построчно, и когда ему встречается сценарий, парсер останавливается, чтобы загрузить файл, прочитать и выполнить его, а затем продолжить обработку остальной части страницы.
Однако в большинстве случаев загрузка JavaScript-файлов может происходить асинхронно, не блокируя работу парсера. Для этого можно использовать атрибуты defer или async.
<script src="path/to/script.js" async></script>
<script src="path/to/script.js" defer></script>
Оба варианта предписывают браузеру загрузить скрипт в фоновом режиме. Разница между ними заключается в том, что async указывает браузеру на выполнение скрипта сразу после его загрузки, а defer - на ожидание завершения работы парсера.
Если веб-страница содержит несколько скриптов, то defer будет выполнять их в относительном порядке, а async будет выполнять тот, который загрузится первым, независимо от их порядка.
В общем случае, если сценарий опирается на полное дерево DOM, то следует использовать defer
, который запускает файл после завершения работы парсера. Если скрипт должен быть выполнен раньше, используйте async
. Если скрипт зависит от других скриптов, которые должны выполняться в их относительном порядке, используйте defer
.
Повышение производительности веб-страниц с помощью подсказок ресурсов
Подсказки ресурсов - это способ разработчиков указать браузеру, как поступать с файлами ресурсов на текущей странице или с теми, которые могут понадобиться в будущем. Иногда ресурс необходимо загрузить как можно быстрее, а иногда он может понадобиться в будущем, и тогда можно загрузить его в фоновом режиме. Подсказки ресурсов указывают браузеру, как обрабатывать эти ресурсы.
Подсказки ресурсов задаются с помощью тега <link>
и должны быть размещены в разделе head
HTML-файла следующим образом:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="dns-prefetch" href="https://style.example.com">
</head>
<body>
. . .
</body>
</html>
Это пример подсказки ресурса dns-prefetch
. Когда браузер посещает веб-сайт, он сначала обращается к DNS-серверу. DNS-сервер - это как телефонная книга для Интернета, которая сопоставляет домены с IP-адресами. Браузер обращается к DNS-серверу с доменом, а DNS-сервер возвращает соответствующий IP-адрес, и браузер может установить соединение с этим IP-адресом. Этот процесс называется DNS-поиском.
Данная ресурсная подсказка, по сути, сообщает браузеру о том, что пользователь, скорее всего, предпримет некоторые действия, которые потребуют от браузера поиска IP-адреса https://style.example.com
. В результате браузер инициирует разрешение доменного имени как можно быстрее и кэширует результат локально. Такое кэширование позволяет браузеру напрямую извлекать IP-адрес из кэша при последующем запросе пользователя.
Кроме dns-prefetch
, существует еще несколько подсказок ресурсов, как показано в приведенном ниже списке:
preconnect
<link rel="preconnect" href="https://style.example.com">
preconnect
- это шаг вперед по сравнению с dns-prefetch
, который просит браузер установить соединение с хост-сервером (так называемое TCP handshake) после завершения поиска DNS. Это соединение происходит один раз для каждого сервера и может занять много времени, если сетевые задержки велики.
preload
<link rel="preload" href="path/to/script.js" as="script">
preload
указывает браузеру, какие ресурсы должны быть получены для текущей веб-страницы. Указанным ресурсам (определяемым по href
) будет присвоен высокий приоритет, и они будут загружены как можно быстрее. preload
также позволяет указать дополнительный атрибут as
, определяющий тип ресурсов. Для разных типов ресурсов могут использоваться разные заголовки запросов и политики безопасности.
На практике для достижения наилучшего пользовательского опыта лучше всего задавать preload
наиболее важных ресурсов, таких как основные CSS и JavaScript, шрифты, а также изображения, которые должны быть отображены при первоначальной загрузке.
prefetch
<link rel="prefetch" href="path/to/style.css" as="style">
prefetch
аналогичен preload
, за исключением того, что в нем задаются ресурсы, которые могут понадобиться пользователю в будущем. Указанным ресурсам будет присвоен низкий приоритет, и они будут загружены после загрузки страницы. Загруженные файлы будут храниться в кэше и будут извлечены, когда пользователь действительно их запросит.
prerender
<link rel="prerender" href="next_page.html">
prerender
указывает браузеру на необходимость загрузки следующей страницы и всех связанных с ней ресурсов, а также их отрисовки в фоновом режиме. Когда пользователь запросит эту страницу, она будет извлечена из фонового режима.
Используйте сеть доставки контента (CDN)
Сеть доставки контента (CDN) представляет собой кластер серверов, распределенных по всему миру. На этих серверах хранятся кэши вашего сайта, и когда пользователь запрашивает веб-страницу, вместо соединения с вашим хостинг-сервером данные будут переданы с ближайшего к пользователю сервера CDN.
Использование CDN (Content Delivery Network) позволяет повысить скорость загрузки сайта, обеспечивая клиентам более комфортные условия работы. Кроме того, это поможет вам минимизировать затраты на пропускную способность, поскольку данные передаются с сервера CDN, а не с вашего хостинг-сервера. Еще одним преимуществом использования CDN является защита сервера от DDoS-атак, что повышает безопасность сайта.
Конечно, нет необходимости создавать такую систему самостоятельно, существует множество провайдеров CDN, таких как CloudFlare, Amazon CloudFront, Google Cloud CDN, Akamai и т.д. Процесс настройки CDN зависит от выбранного провайдера, поэтому для получения более подробной информации следует ознакомиться с их специальной документацией.
Настройте кэширование
Помимо кэширования веб-страниц с помощью CDN, можно сделать контент еще ближе к пользователям, кэшируя ресурсы локально.
Подобно тому, как в HTML-документе есть раздел <head>
, который используется для хранения метаданных о веб-странице, каждый HTTP-запрос/ответ также имеет заголовок, используемый для записи метаданных о запрашиваемых или получаемых ресурсах.
HTTP-заголовок Cache-Control
используется для указания браузеру пользователя, как кэшировать полученные ресурсы.
В зависимости от способа размещения сайта на хостинге могут существовать различные способы добавления пользовательских HTTP-заголовков. В качестве примера можно привести настройку заголовка Cache-Control
при использовании AWS Amplify.
Перейдите в раздел App settings => Custom headers и отредактируйте файл customHttp.yml
:
customHeaders:
- pattern: '**/*.js'
headers:
- key: Cache-Control
value: 'public,max-age=31536000,s-maxage=86400,immutable'
- pattern: '**/*.css'
headers:
- key: Cache-Control
value: 'public,max-age=31536000,s-maxage=86400,immutable'
. . .
В данном примере будут кэшированы все файлы .js
и .css
. public
указывает, что ответ может быть кэширован в общедоступных кэшах (например, CDN). max-age=31536000
устанавливает максимальное время (в секундах), в течение которого файл может быть кэширован в кэше браузера. s-maxage=86400
устанавливает максимальное время (в секундах), в течение которого файл может быть кэширован в общедоступных кэшах. И, наконец, immutable
указывает на то, что содержимое файла неизменяемо и не будет меняться с течением времени. Это важно для оптимизации поведения кэша.
Если на вашем сайте есть файл .htaccess
, то попробуйте сгенерировать соответствующий код с помощью этого генератора .htaccess
.
Пора отказаться от Google Analytics
Все ненавидят Google Analytics 4, поэтому давайте откажемся от них!
Существует множество хороших, легких и открытых альтернатив Google Analytics, таких как Plausible, Matomo, Fathom, Simple Analytics и др. Многие из них имеют открытый исходный код и могут быть размещены самостоятельно.
Используя эти варианты с открытым исходным кодом, вы получите значительно меньший по размеру скрипт отслеживания. В качестве примера можно привести Plausible, скрипт которого занимает всего 1 КБ, в то время как Google Analytics - более 300 КБ.
Однако стоит отметить, что, хотя эти варианты с открытым исходным кодом и хороши, возможно, что Google Analytics предоставляет некоторые уникальные возможности, которые в настоящее время не предлагаются альтернативными вариантами. Поэтому, прежде чем переходить на новый вариант, стоит сначала опробовать его и убедиться, что он соответствует вашим требованиям.
Действительно ли Вам нужен полнофункциональный сайт?
При создании своего первого сайта многие выбирают полноценную CMS, например WordPress, Squarespace или Wix. Однако эти платформы часто оказываются более раздутыми, чем это необходимо, поскольку они должны удовлетворять самым разным требованиям. Например, если вы хотите создать что-то простое, например, базовый персональный блог или портфолио, лучше использовать генератор статических сайтов, такой как Hugo или Jekyll.
Основное их отличие заключается в том, что WordPress создает полнофункциональный сайт с фронтендом, бэкендом и базой данных. Когда пользователь запрашивает страницу, бэкенд извлекает необходимые данные из базы данных, компилирует их в веб-страницу и передает на фронтенд.
В то время как генератор статических сайтов не требует наличия базы данных, он просто генерирует все статические веб-страницы на этапе сборки, а при запросе пользователя просто выдает заранее созданную страницу на фронтенд. В результате статический сайт требует значительно меньше ресурсов для размещения.
Однако недостатком статических генераторов сайтов является сложная кривая обучения. Эти инструменты, как правило, не имеют удобных функций перетаскивания, которые есть в WordPress и Wix, и требуют определенных навыков программирования для настройки внешнего интерфейса.
Дальнейшие шаги
В этой статье мы рассмотрели несколько способов оптимизации сайта для достижения более высокой скорости загрузки и улучшения качества работы пользователей. Однако важно отметить, что данное руководство не содержит всех деталей. Возможно, существуют и другие методы оптимизации, зависящие от конкретных требований вашего проекта. Если вам известны дополнительные методы оптимизации сайта, пожалуйста, поделитесь ими в комментариях ниже. Я с удовольствием включу их в данное руководство для пользы наших читателей.
Кроме того, в ходе подготовки этой статьи я наткнулся на несколько ценных источников, которые, как мне кажется, могут оказать вам дополнительную помощь:
Спасибо за прочтение!