Сейчас популярно мнение, что текущие Javascript-фреймворки непомерно большие, а новый фреймворк Svelte очень компактный. Поэтому всем нужно переходить на него, и проблема размера Javasctipt решится сама собой.
Недавно вышла статья "Хороший ли выбор Svelte для реализации виджета?" с опытом реализации проекта с критичным размером бандла. Это отличный повод проверить обещания пиарщиков Svelte на реальном проекте.
Давайте его проанализируем!
Исходные данные
Рассматриваемый проект – это встраиваемый виджет, распространяется как монолитный Javascript-бандл общим размером в 71 Кб (c учётом gzip). Много это или мало? В статье "Цена JavaScript в 2019 году" была рекомендация избегать бандлов больше 50-100 Кб. То есть текущий проект находится в жёлтой зоне, размер ещё приемлемый, но уже пора задуматься, о том как в него добавить новой функциональности, и при этом уместиться в верхний лимит в 100 Кб.
Теперь скачаем этот скрипт, отформатируем его и посмотрим, что там интересного.
Настройки бандлера
Первое, что бросается в глаза при просмотре кода – повторение вот такого паттерна:
function (t, e, n) {
t.exports = {
// какой-то код
}
}
Это очень похоже на CommonJS модуль. Однако в современных проектах рекомендуется использовать ES-модули, потому что этот формат обеспечивает возможность для оптимизаций – Scope hoisting и Tree-shaking. В случае CommonJS-модулей, бандлеры оптимизировать их не могут и выдают больше кода на выходе.
Иногда ещё может получиться так, что вы используете ES-модули в своем коде, а бандл все равно выходит не оптимизирован. В этом случае полезно запустить webpack с флагом --display-optimization-bailout и посмотреть, что пошло не так с оптимизациями.
Неправильно настроенный бандлер может разрушить всю "магию исчезновения" Svelte, которая целиком основана на описанных выше оптимизациях, поэтому в случае ошибок в конфигурации к вам в бандл попадёт весь фреймворк целиком.
К сожалению, у меня нет доступа к исходному коду, поэтому посмотреть на их настройки не получится, но по моему опыту правильно настроенные оптимизации позволяют сократить бандл на 20%, сбросив 14 Кб из общего размера виджета.
Оптимизация ресурсов
Далее мы замечаем, что в бандл включены SVG и JPG изображения. Очень важно, чтобы для веба ресурсы были правильно оптимизированы и весили как можно меньше.
Начнем с SVG. Для его оптимизации есть инструмент SVGO, также доступна онлайн-версия.
Всего в бандле нашлось 7 svg-файлов общим весом в 10 Кб, и, по-видимому, разработчики не занимались их оптимизацией. Пропустив их через SVGO удалось уменьшить общий размер на 3 килобайта.
Теперь про JPG. Заметим, что картинки загружаются в блок размером 59х27 пикселей, а сами оригиналы 183x72. Избыточный размер, даже с учетом поддержки retina-экранов. Кроме того, есть шансы улучшить размер подбором более оптимальных форматов сжатия. Очень удобно это делать в веб-приложении https://squoosh.app/, которое позволяет пережать изображения прямо в браузере с использованием различных кодеков. Применив его к картинкам из виджета, сокращаем их размер на треть, получая еще 7 килобайт экономии.
Чтобы не тратить время на оптимизацию каждого изображения вручную, рекомендуется добавить процесс оптимизации в свою сборку, SVGO уже упоминался выше, а для растровых картинок есть imagemin.
Ненужный код
Теперь переходим к разбору собственно Javascript. Там встречается нетранспилированный ES6-код, а значит поддержка IE от разработчиков не требовалась. И это действительно хорошая стратегия уменьшить размер кода – по моим данным, использование ES6 сокращает размер кода на 7%. Если вам не нужно поддерживать Internet Explorer, это может оказаться очень хорошим подспорьем.
Далее обратим внимание на используемые библиотеки.
- axios – библиотека для http-запросов. Поскольку вопрос поддержки IE не стоит, авторы могли использовать нативное Fetch API, а не брать эту зависимость, которая весит 4 Кб.
- process – полифилл объекта process из Node.js. Обычно включение этой зависимости является следствием неправильной конфигурации webpack, который видит
process.env.NODE_ENV
, и добавляет полноразмерный полифилл дляprocess
вместо одного только объектаprocess.env
. Избавление от этого модуля сэкономит нам еще 1 килобайт. - sentry – трекинг пользователя. Не будем здесь обсуждать хорошо ли следить за пользователями, но посмотрим как избежать этих 17 килобайт в бандле.
- Sentry предлагает вариант загружать скрипт с их CDN. Здесь этот вариант помог бы, потому что скрипт скорее всего уже загружен в кэш пользователя на других сайтах, и время загрузки страницы сократится.
- Здесь ещё стоит объяснить, почему обычно не рекомендуется загружать библиотеки с чужих CDN, а здесь это приемлемо. Дело в том, что библиотека предназначена для отправления данных на сервера Sentry. Поэтому у вас в любом случае есть зависимость от их сервиса, неважно загружаете ли вы скрипт со своего сервера или их CDN.
Code coverage
Еще полезно прогнать код через Code Coverage из Chrome Devtools. Для этого виджета инструмент показывает, что 24% Javascript не используется. Это не обязательно означает, что весь неиспользуемый код можно удалить, возможно, он нужен для обработки ошибок и других пограничных случаев, но это хороший сигнал обратить на него внимание и подумать, а зачем этот код вообще нужен.
Итог
Итого, оптимизации позволили бы сократить размер этого виджета на 46 килобайт (более чем в 2 раза!)
- 14 Кб – настройка бандлера
- 10 Кб – оптимизация изображений
- 22 Кб – Javascript-зависимости
Таким образом, мы видим, что на размер бандла влияет множество факторов, и эффект от использования Svelte примерно как от запивания гамбургера диетической колой – исключительно психологический. Реальная оптимизация требует внимания к деталям и контролю размера на выходе.
А если вы задумываетесь о переходе на Svelte ради уменьшения размера своего проекта – советую обратить внимание на пункты выше, возможно, если их исправить, то никуда переходить и не понадобится.
Автор: Борис Сердюк