Pull to refresh

Избавляемся от дублей пакетов в бандлах

Reading time 3 min
Views 10K

Существует много webpack пакетов находящих дубли в бандле, самый популярный из них duplicate-package-checker-webpack-plugin, но он требует пересборки проекта, а так как стояла задача автоматизировать подбор оптимальной версии пакетов, то и вовсе получилось свое альтернативное решение.


Ну или моя история как получилось уменьшить бандл на 15%, за несколько секунд.


боль


Как и во многих крупных компаниях у которых есть огромная кодовая база, много единой логики, как следствие используем общие компоненты, публикуемые в свой npm репозиторий. Публикуются они через lerna, соответственно перед каждой установкой или обновлением общих компонентов возникает вопрос, какую версию устанавливать. lerna перепаблишивает все компоненты, которые используют публикуемый компонент (если версия до этого последняя была). Соответственно, всегда есть версии нескольких компонентов, которые лучше подходят друг к другу, так как не конкурируют зависимостями.


Из open source проектов подобным образом паблишиться nivo, вот их конфиг lerna.


Как появляются тогда дубли зависимостей? И как их устранять?


Предположим, у вас есть простой проект со следующим package.json:


{
  "name": "demo-project",
  "version": "1.0.0",
  "dependencies": {
    "@nivo/bar": "0.54.0",
    "@nivo/core": "0.53.0",
    "@nivo/pie": "0.54.0",
    "@nivo/stream": "0.54.0"
  }
}

Посмотрим, где используется @nivo/core:


npm list @nivo/core


Видим 4 копии @nivo/core (3 экземпляра 0.54.0 и 1 — 0.53.0). Но если мы поменяем минорную версию @nivo/core на 0.54.0, дубли устранятся.



Текущий пример прост, но на практике, естественно зависимостей у каждого пакета больше, и еще нужно рассмотреть подзависимости дальше, что увеличивает сложность задачи.


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


Вообще правильно сразу обновлять пакеты до последней версии, но времени как всегда нет, чтобы менять мажорные версии, а в слепую подбирать перебором подходящий пакет долго и сложно. Ведь нужно обновить версию зависимости в package.json, установить новые зависимости, и после проверить исчезли ли дубли в билде, если нет — повторить, долго, в среднем минуты 3-4 на итерацию.


Все это монотонно и требует внимательности, поэтому решил автоматизировать.


Хотелось бы узнать дубликаты без переустанавки зависимостей, и пересборки проекта, в идеале cli приложение выводящее варианты оптимизаций за 10 секунд и все существующие дубли в проекте.


Устранение дублей можно поделить на несколько подзадач, рассмотрим их по порядку.


Первая задача. Нужно смоделировать будущее дерево зависимостей бандла только по package.json, учитывая стандартный dedupe, быстро, не более чем за 100ms.


Решил использовать package-json для получения информации по пакетам и semver для сравнения различных версий.


В итоге получился npm пакет dependencies-tree-builder, шустро моделирующий дерево зависимостей бандла только по package.json.


Выделил в отдельный компонент, ибо может быть кто-нибудь переиспользует его в комбинаторных задач с package.json.


Вторая задача. Комбинаторная задача, эффективный перебор вариантов изменения зависимостей, и сравнение нескольких вариантов деревьев, ну и естественно выбор оптимального.


Надо было как-то сравнивать качественно получившейся деревья, и пришлось позаимствовать идею энтропии, как количественное измерение беспорядка, взял сумму экземпляров дублей (из примера выше она равна 3).


Было бы здорово еще учитывать веса пакетов (в КБ), но к сожалению, пакета который бы быстро работал с весами я не нашел, а те что есть работают примерно по пол минуты на пакет, к примеру package-size. Так как работают по следующему принципу: создают проект с единственной зависимостью, устанавливают зависимости, после измеряется суммарный вес папки. В итоге, другого критерия, как количество экземпляров дублей не придумал.


Чтобы понять какой пакет нужно изменить, рассматриваются причины дублей, конкретнее источник и эффект. Перебором устраняются дубли эффектов, насколько это возможно, а так как эффекты устраняются, то и дубли в последствии тоже.


В итоге, получилось небольшое cli приложение ostap, рекомендующее оптимальные версии для уменьшения количества экземпляров дублей в бандле.


Запускается просто указанием на package.json вашего проекта.


ostap ./package.json


Еще можно использовать для быстрого просмотра всех будущих дублей без пересборки проекта меняя лишь версии в package.json.


ostap ./package.json -s


По итогу, в моем проекте суммарный вес бандлов снизился на 15%.


В репозитории есть раздел quick start.


Если используете route-splitting, может показаться, что какие-то бандлы увеличились в весе, но возможно изменилось распределение компонентов. То есть вместо копий зависимостей на каждой странице, единственная версия перешла в общий бандл для всех страниц, поэтому нужно оценивать суммарный вес бандлов по всем страницам.


Надеюсь, статья была полезной. И кому-то информация сэкономит время. Спасибо.


Еще раз ссылочки для удобства:


  • Пакет моделирующий дерево зависимостей бандла по package.json
    GitHub;
  • Оптимизатор зависимостей для устранения дублей в бандле
    GitHub.

Если есть интересные идеи пишите в issue на github'е, обсудим.

Tags:
Hubs:
+24
Comments 29
Comments Comments 29

Articles