Возможно, вам не нужен Svelte, чтобы уменьшить ваш JavaScript

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


    Недавно вышла статья "Хороший ли выбор 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 Кб.
    • query-string – библиотека для разбора query-параметров. Может быть заменена на нативным API URLSearchParams и сэкономить вам 2 килобайта
    • process – полифилл объекта process из Node.js. Обычно включение этой зависимости является следствием неправильной конфигурации webpack, который видит process.env.NODE_ENV, и добавляет полноразмерный полифилл для process вместо одного только объекта process.env. Избавление от этого модуля сэкономит нам еще 1 килобайт.
    • lodash/debounce. Во-первых, здесь должна использоваться версия lodash-es, чтобы применялись оптимизации для es-модулей. Во-вторых, реализация этой функции в lodash это вот такая простыня кода, которая занимает 1 килобайт в бандле. Для типичной задачи "не отсылать запрос на сервер на каждое нажатие клавиши" можно обойтись вот этой реализацией весом в 100 байт, в 10 раз меньше.
    • sentry – сбор Javascript ошибок. Эта функциональность не является критически важной для виджета, поэтому посмотрим, как убрать её из первоначальной загрузки и сэкономить 12 килобайт:
      • Sentry предлагает вариант загружать скрипт с их CDN. Здесь этот вариант помог бы, потому что скрипт скорее всего уже загружен в кэш пользователя на других сайтах, и время загрузки страницы сократится.
      • Здесь ещё стоит объяснить, почему обычно не рекомендуется загружать библиотеки с чужих CDN, а здесь это приемлемо. Дело в том, что библиотека предназначена для отправления данных на сервера Sentry. Поэтому у вас в любом случае есть зависимость от их сервиса, неважно загружаете ли вы скрипт со своего сервера или их CDN.

    Спасибо eilemust за предоставленный скриншот результатов webpack, после которого эта секция была дополнена


    Code coverage


    Еще полезно прогнать код через Code Coverage из Chrome Devtools. Для этого виджета инструмент показывает, что 24% Javascript не используется. Это не обязательно означает, что весь неиспользуемый код можно удалить, возможно, он нужен для обработки ошибок и других пограничных случаев, но это хороший сигнал обратить на него внимание и подумать, а зачем этот код вообще нужен.


    Итог


    Итого, оптимизации позволили бы сократить размер этого виджета на 44 килобайта (более чем в 2 раза!)


    • 14 Кб – настройка бандлера
    • 10 Кб – оптимизация изображений
    • 20 Кб – Javascript-зависимости

    Таким образом, мы видим, что на размер бандла влияет множество факторов, и эффект от использования Svelte примерно как от запивания гамбургера диетической колой – исключительно психологический. Реальная оптимизация требует внимания к деталям и контролю размера на выходе.


    А если вы задумываетесь о переходе на Svelte ради уменьшения размера своего проекта – советую обратить внимание на пункты выше, возможно, если их исправить, то никуда переходить и не понадобится.

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 26

      +1
      Это очень похоже на CommonJS модуль. Однако в современных проектах рекомендуется использовать ES-модули

      Ну нет, CommonJS модуль выглядит по-другому. То, что вы смотрите — это уже сбандленный модуль, и он выглядит для CommonJS и ES одинаково.

        0

        Почему вы так считаете? t.exports – это минифицированная версия module.exports. А для es-модулей webpack генерирует совсем другое. Например, для export default { value: 42 }; получится:


        __webpack_require__.r(__webpack_exports__);
        /* harmony default export */ __webpack_exports__["default"] = ({ value: 42 });

        После минификации t.exports там быть по определению не может.

          0
          Это не вебпак, а Rollup.
        +8

        Sentry — трекинг пользователя? Это система для сбора ошибок как с фронта, так и с бекенда и мобильных приложений

          –7

          А в чем принципиальная разница? Sentry тоже собирает какие-то данные о пользователях в целях аналитики.

            +11
            … принципиальная — в предназначении (основной цели).
            Строго говоря, error.log сервера тоже «собирает какие-то данные о пользователях в целях аналитики». Мне кажется, в вашей формулировке сместился смысл, и незнакомому с предметом читателю может показаться, что Sentry — это просто какой-то более другой Google Analytics. Было бы полезно исправить этот момент.
              –3

              Так мое мнение такое и есть, что Sentry – это система аналитики, просто с фокусом на сбор информации об ошибках. Однако стандартным набором – идентификацией пользователей и записью их действий – они тоже занимаются. IANAL, но вроде бы с точки зрения какого-нибудь GDPR разницы между Google Analytics и Sentry нет никакой.

                0

                Почитал немного матчасти по этому поводу. В интернете есть много списков хостов для использования блокировщиками рекламы, и там нет однозначного мнения по поводу Sentry. Тема довольно холиварная, есть мнения за и против:



                Я понимаю, что это сервис для разработчиков, и он не занимается рекламным маркетингом. Однако, технически им ничего не мешает переобуться в воздухе, и начать продавать данные пользователей на сторону, на серверах-то они имеются.


                В статье этот момент оставлю как есть. Можете считать это авторским личным мнением.

                  +8
                  … имеете право :)
                  Но все же будет честным отметить, что Sentry не «передает в свою систему для анализа о любом посетителе» ни байта — до тех пор, пока у посетителя не произошла ошибка. Такое поведение — следствие ее основного предназначения, и этим Sentry и аналоги принципиально отличаются от Google Analytics и какого-нибудь Amplitude сотоварищи.
                    –4

                    Спасибо за интересное мнение с противоположной стороны :)

                      +4

                      Sentry вообще можно сделать self hosted, поэтому не очень понятно как они могут переобуться.

                      +1

                      Скорее, пока разработчики не решили что-то передавать. А там, что захотят, то и передадут. В этом основное отличие от GA по-моему

            +1
            А если вы задумываетесь о переходе на Svelte ради уменьшения размера своего проекта – советую обратить внимание на пункты выше, возможно, если их исправить, то никуда переходить и не понадобится.

            Я правильно понимаю, что тут говорится «оптимизированный vue/react меньше неоптимизированного svelte», ну для честности надо оба оптимизированные или неоптимизированные сравнивать то.
              0

              Статья не ставит целью сравнить один фреймворк с какими-то другими. Здесь скорее совет, на чем акцентировать внимание – на оптимизации ассетов, или миграции на другой фреймворк. Конечно же, лучше и то, и другое сразу, но если нужно расставить приоритеты, то с чего начать?

              +2
              Вот правда не могу понять — действительно стоит тратить время на подобные оптимизации?
              Тем более если трафик в основном идет на картинки и шрифты.

              Ради интереса проверил сколько весит js у первых попавшихся сайтов:
              habr — 200k, google поиск — 400kb, youtube — 1.8Mb, gmail — 3.2Mb
              Если светила it не сильно обеспокоены оптимизациями, стоит ли нам?
              Если важно показать контент до обработки js — используйте next.js, прекрасная и очень простая штука.
                0
                каким способом проверяли?
                  0
                  Chrome devtools network
                  +2
                  Если светила it не сильно обеспокоены оптимизациями, стоит ли нам?

                  А вы точно размером с gmail, который может себе позволить грузить 6.7Мб скриптов (не 3.2, 3.2 — это только чтоб показать вам «голый» интерфейс даже без писем, потом там еще несколько мегабайт жса придёт)? Просто потому, что куда же пользователи денутся с подводной лодки?
                    +4

                    а потом сайты не грузятся на едва живом 2g (реальный случай конца 2019 года)

                      0
                      Все зависит от специфики и бизнес требований. В идеальном мире, конечно, хотелось бы всегда и везде иметь progressive web apps, которые хороши и на 2G и на 5G, но на практике если таких посетителей 1 человек в месяц (условно), то нету никакого профита (для бизнеса) вкладывать деньги в разработку комплексного решения (увы).
                        –1

                        ну так пользователи с едва живым 2g принесут прибыли скорее всего меньше (в десятки раз?) чем зарплата за N часов работы программистам за их работу по оптимизацию

                      +2
                      Я автор статьи "Хороший ли выбор Svelte для реализации виджета?".

                      1. В этой статье, автор говорит про пакеты, но не упоминает query-string, который в виджете также используется. Можно его тоже выкинуть и парсить строку вручную (-2кб). И Axios/Svelte/«Все, что используется для ускорения разработки» — выбросить, оно тоже место занимает.

                      2. Использовать sentry в cdn? Какая вероятность, что у пользователя будет закеширована версия sentry, которая используется в виджете? Какая вероятность, что origin cdn в виджете и origin cdn на других страницах интернета, будет один и тот же? Я думаю, чуть больше, чем sentry, встроенный в виджет, но не сильно.

                      Тут еще можно добавить, к sentry в бандле можно применить tree-shaking, а к sentry в cdn — нельзя. Если говорить про виджет, sentry там занимает 12.5 кб.

                      3.
                      сократить бандл на 20%, сбросив 14 Кб из общего размера виджета.



                      Тут явно видно, что не является модулем, который можно оптимизировать. Надеюсь, больше не кажется, что можно убрать 14кб.

                      Итого: можно сократить 10 кб на картинках, но не 46 кб.
                        0

                        Спасибо за предоставленный скриншот вебпака. Обновил статью с его учетом. Теперь по пунктам:


                        «Все, что используется для ускорения разработки» — выбросить, оно тоже место занимает.

                        Не выбросить, а заменить на нативные API. URLSearchParams прекрасно заменяют функциональность query string


                        Использовать sentry в cdn?

                        А почему нет? Сможет ли пользователь заказать себе такси, если sentry не загрузится? Скорее всего, да. Тогда зачем его обременять лишним кодом? Пусть он загружается асинхронно, чтобы не отнимал время загрузки у тех, у кого канал потоньше. Вы же загружаете скрипт Google Tag Manager асинхронно, тогда почему не сделать так же с Sentry?


                        Если говорить про виджет, sentry там занимает 12.5 кб.

                        А в эти 12 килобайт входит tslib? Это еще 4 килобайта сверху, если нет.


                        Тут явно видно, что не является модулем, который можно оптимизировать. Надеюсь, больше не кажется, что можно убрать 14кб.

                        • Lodash.debounce – нужно использовать lodash-es, чтобы включить оптимизации es-модулей. А лучше вообще заменить его на свой 100-байтный велосипед, польза библиотечного debounce сильно переоценена.
                        • Все картинки. Нужно обновить file-loader до 5 версии чтобы он начал генерировать es-модули для файлов.

                        В идеале, этого желтого цвета быть вообще не должно. Если какая-то библиотека не поставляет es-модули – то это первый кандидат на вылет и поиск более современной замены.


                        --


                        После добавления lodash и query-string и уменьшения sentry до 12 кб финальный результат стал на 2 килобайта меньше, но это все еще 44 кб, и с этим по-любому что-то надо делать.

                          +5
                          Не выбросить, а заменить на нативные API. URLSearchParams прекрасно заменяют функциональность query string

                          Всё было в этой стате было хорошо ровно до секции Ненужный код. К сожалению, ни одна из предложенных нативных альтернатив не заменяет существующие решения, иначе бы все давно на них перешли. И дело здесь далеко не в IE, а в банальном отстутсвии паритета возможностей которые предлагают сторонние библиотеки.
                          Вы не можете заменить Axios на Fetch и ожидать такой же функциональности. Fetch не поддерживает прогресс загрузки в обе стороны (только на получение), поддержка отмены запросов в Fetch (AbortController) сильно отличается от поддержки самого Fetch, Axios обрабатывает 4xx\5xx коды ответа иначе чем Fetch.
                          URLSearchParams работает исключительно со строками, тогда как query-string с примитивами и объектами и умеет самостоятельно их преобразовывать.


                          Куда действительно можно посмотреть в целях оптимизации — это в исключение изображений и CSS из бандла потому что сейчас они проходят парсинг в два этапа: сначала JS парсером, затем парсером под конкретный тип данных.

                            +2

                            Конкретно в этом проекте нативных API хватает за глаза. Собрать JSON, отправить POST на сервер – с этим Fetch справляется прекрасно. С query-string то же самое – в этом проекте только строки и нужны, сложные объекты там не используются.


                            Проблема в том, что эта лишняя функциональность занимает место в бандле совершенно зря. В результате пользователи страдают и пишут посты вроде такого. Хотя проблема решается очень просто – не надо тянуть сложные зависимости раньше времени.

                              +2

                              Во многом я соглашусь с автором статьи — сторонние либы и плохо настроенный бандлер это главные причины убивания плюшек Svelte. Отчасти по этому Rollup бывает предпочтительнее из-за того что он лучше делает tree shake но конечно главное тут что вам совершенно не нужен axios для этого виджета. Я понимаю что скорее всего вы копипастили код из других своих проектов на React но все же для целей экономии тут можно было бы немного доработать.
                              В любом случае я рад что вы воспользовались Svelte и у вас получился хороший и работающий виджет.

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                        Самое читаемое