При загрузке сайта на сервер ложится множество задач, которые необходимо выполнять быстро и стабильно. Но ответственность за часть из них (например, обработку запросов на получение файлов, их пересылку клиенту и компрессию передаваемых данных) можно переложить на специализировые файловые хранилища. Они, как правило, имеют несколько территориальных зон и отдают клиенту файлы от наиболее близкого сервера (так, время загрузки ресурсов из физически удаленных от расположения основного сервера мест значительно сократится). Эти преимущества использования CDN — разгрузка сервера, сокращение времени доставки контента, а также сокращение трафика, передаваемого основным сервером (который обычно дороже), привели к довольно широкому использованию подобного подхода. Сегодня разберемся, как работать с Amazon S3-совместимыми CDN и настраивать передачу сжатых файлов. На данный момент существует 2 распространенных в веб-среде стандарта — Gzip и Brotli. Второй отличается более эффективной компрессией (на 15-20%), но работает только по HTTPS (за исключением localhost, где работает и по HTTP) и в достаточно свежих браузерах (> IE 11). Некоторые CDN (Amazon CloudFront) поддерживают сжатие "на лету", но только в формате Gzip, в то время как другие (я использую Yandex Object Storage) лишены подобной логики, представляя собой просто облачные папки с файлами без какой-либо логики, кроме распределенной по регионам доставки. Соответственно, необходимо генерировать сжатые файлы самостоятельно, например, используя плагин compression-webpack-plugin: Эти плагины, разумеется, нужны только для фронтендовой сборки (при использовании изоморфных сборок) и их следует отключать для ускорения процесса локальной сборки, например, с помощью env-переменной: Основной вопрос, на который нужно ответить в этом разделе — это на каком этапе загружать сгенерированные файлы в распределенное хранилище. Схемы может быть две: Второй вариант практически не содержит подводных камней: если использовать contenthash в названии файлов, то новые файлы не будут перезатирать старые, таким образом отсутствует возможность порчи параллельно запущенных серверов с разными версиями; откаты на предыдущие версии (если сервер не запустился) беспроблемны; недоступность CDN для загрузки файлов (такое бывает, технологии не безупречны) приведет лишь к отсрочиванию релиза, не повлияв на текущий работающий функционал. Для начала необходимы следующие настраиваемые переменные (архитектура сборки взята отсюда): При выключенной настройке CDN_ENABLED для удобной локальной разработки нужно будет учесть схему раздачи статики непосредственно основным сервером. CDN_BUCKET_PREFIX сделан для возможности работы нескольких проектов / отдельных сервисов в рамках одного и того же хранилища.  Далее необходимо установить aws-sdk, подключиться и создать методы для создания bucket и загрузки файлов: Далее в рецепт запуска сервера необходимо включить логику загрузки файлов: Логика кода следующая: Теперь при запуске / перезапуске сервера с включенной настройкой CDN_ENABLED файлы загружаются в стороннее хранилище. При отдаче html-шаблона на первоначальный запрос от клиента при включенной генерации сжатых файлов необходимо заменить расширения файлов в тегах script и link на соответствующие версии. Важно при этом учитывать возможность клиента с ними работать, о чем он сообщает в заголовке Accept-Encoding: CDN не может сам отдавать необходимую сжатую версию, поэтому необходима эта небольшая модификация шаблона. При использовании системы кеширования это действие должно выполняться после нее, чтобы клиенту случайно не были выданы файлы в неподдерживаемом формате. Предполагается, что данный режим будет использоваться только при локальной разработке, а сжатие файлов при этом будет включаться только для дебага. Тем не менее, при сбое работы CDN можно легко переключить на сервере env-параметр и запустить этот режим. Схема работы: На данный момент файлы сжаты и лежат на стороннем сервере, соответственно осталось лишь изменить ссылки с относительных от текущего домена. Заменой шаблона как выше это сделать не получится, так как дополнительные ресурсы (изображения, например) и асинхронные чанки могут там не присутствовать, поэтому необходимо глобально заменить publicPath в конфиге Webpack: Это последний шаг настройки, в итоге при включенных соответствующих настройках при загрузке страницы получаем ссылки на ресурсы следующего вида: И получаем все преимущества — хорошую контролируемую компрессию, ускорение загрузки ассетов из других регионов, уменьшение нагрузки на основной сервер и, как правило, более дешевый трафик, при этом не поступаясь удобством локальной разработки в режиме отдачи статики своим сервером. Остался лишь один очевидный сайд-эффект: асинхронно загружаемые чанки запрашиваются в несжатых версиях, так как не проходят через сервер, способный определить Accept-Encoding и перенаправить на соответствующую версию. Как правило, в архитектурах, работающих по lazy-паттерну, уже закладываются механизмы для смягчения падения производительности при дозагрузке, поэтому небольшое дополнительное время (которое будет заметно только при медленном интернете у клиента) не станет проблемой. Но так как в большинстве проектов такой паттерн не используется, то лишь немногие столкнутся с этим. Совет напоследок — не поленитесь измерить скорость отдачи статики в текущем режиме работы в вашем проекте при открытии сайта из целевых регионов (есть инструменты, предоставляющие эту возможность бесплатно). Не все CDN-серверы одинаково хороши, и, несмотря на очевидные преимущества "на бумаге", результат на практике не всегда впечатляющ при использовании высокодоступного и быстрого хостинга и основном потоке клиентов из локального региона. Репозиторий Высокодоступного кодинга! Front-end архитектор