С момента его первоначального выпуска мы несколько раз рефакторили наш JavaScript SDK и писали о том, как предыдущие улучшения сокращали время выполнения с 200 мс до 20 мс.

С тех пор размер JavaScript SDK увеличился, поскольку мы добавили поддержку новых интеграций режим устройства. Он стал достаточно громоздким, чтобы начать влиять на время загрузки, поэтому недавно мы представили новую, оптимизированную версию SDK.

Здесь я подробно опишу улучшения, сделанные с помощью этого рефакторинга, пройдусь по процессу принятия решений нашей командой, обрисую компромиссы, которые мы рассмотрели, и продемонстрирую результаты нашей работы.

Ключевые улучшения

Чтобы оптимизировать размер SDK и повысить его производительность, мы сосредоточились на трех ключевых элементах:

  • Освобождение SDK от всего кода интеграции при сборке.
  • Списание технического долга
  • Замена зависимостей сторонних пакетов

Освобождение SDK кода интеграции при сборке

Вместо статического импорта модулей интеграции режима устройства в основной модуль модули интеграции теперь встроены в независимые плагины (скрипты), которые можно легко загрузить на стороне клиента. Как только вызывается `load` API SDK, необходимые целевые интеграции идентифицируются из исходной конфигурации (извлекаются из плоскости управления), и их подключаемые модули асинхронно загружаются один за другим из размещенного местоположения*. По истечении тайм-аута успешно загруженные модули интеграции инициализируются для продолжения пересылки событий.

*По умолчанию в качестве размещенного местоположения используется CDN RudderStack. В случае пользовательского размещенного местоположения это можно переопределить с помощью параметра'destSDKBaseURL'в вызове'load'. Кроме того, SDK определяет этот URL-адрес на основе тега сценария, который добавляет SDK на веб-сайт (при условии, что имя файла по-прежнему “rudder-analytics.min.js”).

Списание технического долга

Мы убрали из SDK как можно больше наворотов. Это включало мертвый, избыточный и устаревший код, а также устаревшие функции автоматического отслеживания.

Замена зависимостей сторонних пакетов

По возможности мы заменили сторонние зависимости пакетов более легкими. В нескольких случаях потребовались специальные реализации для достижения желаемых результатов.

Почему мы остановились на таком подходе?

По замыслу все интеграции режимов устройств независимы друг от друга, поэтому не имело смысла связывать все вместе как единое целое. Более того, поскольку каждый клиент будет подключать к своему JS/веб-источнику только подмножество интеграций режима устройства, загрузка только необходимых интеграций на своем сайте является идеальным сценарием. Эти улучшения также включали минимальные изменения в нашем SDK и процессах по сравнению с другими альтернативами.

Одной из альтернатив, которые мы рассматривали, было динамическое создание SDK с необходимыми интеграциями при отправке запроса на https://cdn.rudderlabs.com/v1.1/rudder-analytics.js/<write key>. При таком подходе интеграции режима устройства упаковываются вместе с основным пакетом SDK и доставляются на основе ключа записи, указанного в URL-адресе.

Мы увидели несколько недостатков этого подхода:

  • Затраты на CDN возрастут, потому что нам придется кэшировать разные версии SDK для каждого ключа записи.
  • Мы не сможем использовать кеширование браузера на различных веб-сайтах, которые посещает пользователь.
  • Миграция существующих пользователей будет сложной задачей

На какие компромиссы нам пришлось пойти?

К счастью, этот рефакторинг не привел к серьезным компромиссам, но стоит отметить два:

  • Затраты на CDN. Размещение всех отдельных SDK для интеграции в режиме устройства означает увеличение затрат на CDN. К счастью, дополнительные расходы не являются значительным бременем.
  • Затраты на миграцию. Чтобы сделать переход на версию 1.1 выгодным для наших клиентов, мы знали, что нам необходимо (1) значительно улучшить производительность по сравнению с версией 1 и (2) максимально упростить переход. Нам удалось внести существенные улучшения, о которых я расскажу ниже, и мы работали над тем, чтобы сделать миграцию максимально безболезненной. В большинстве случаев миграция выполняется за несколько простых шагов, которые мы задокументировали в руководстве по миграции, чтобы помочь клиентам во всех сценариях развертывания.

Проблемы, которые мы должны были решить

В v1 все интеграции были экспортированы из своего модуля как тип по умолчанию. Нам пришлось преобразовать их все в именованные экспорты, чтобы они загружались динамически. См. приведенный ниже пример:

Тип по умолчанию

import Amplitude from "./browser";
export default Amplitude;

Именованный экспорт

import Amplitude from "./browser";
export { Amplitude };

Кроме того, нам пришлось написать скрипт для создания всех отдельных интеграций за один раз. Это то, что позволяет нам развертывать интеграции вместе с основным SDK.

Результаты рефакторинга

Наш новый SDK легче и быстрее предыдущей версии. Чтобы представить это в цифрах:

  • Мы уменьшили размер SDK на 70%. (от 114 КБ до 34 КБ)
  • Время загрузки SDK на 80 % быстрее (с 9,44 мс до 1,96 мс).
  • Время оценки сценария на 28 % меньше (с 86 мс до 63 мс).

Посмотрите PR для рефакторинга на Github.

Первоначально этот блог был опубликован по адресу:
https://www.rudderstack.com/blog/refactoring-rudderstack-s-high-performance-javascript-sdk