awesome-everything EN
↑ Обратно к восхождению

Производительность

Third-party scripts: тихий убийца бюджета

Суть Analytics, реклама, chat-виджеты и A/B testing-инструменты регулярно добавляют 500 КБ-1 МБ на страницу — вне твоего контроля, но внутри цены юзера. Три паттерна их нейтрализуют.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min

Команда тратит спринт, срезая app bundle с 800 КБ до 350 КБ. Lighthouse улучшается на 12 баллов. Через неделю data-команда добавляет Segment, Hotjar и новый Intercom widget — суммарно 450 КБ. Работа спринта стёрта. Никто не заметил, потому что third-party scripts не в репозитории приложения.

Third-party налог

Большинство production-веб приложений грузят 5-15 third-party scripts per page. Популярные и их примерные размеры:

  • Segment analytics: ~150 КБ
  • Hotjar recording: ~200 КБ
  • Intercom chat widget: ~200 КБ
  • Google Tag Manager (с несколькими tags): ~500 КБ+
  • Full Optimizely A/B testing: ~400 КБ
  • Один плохо оптимизированный ad tag: ~300 КБ

Десять средних скриптов × 100 КБ = 1 МБ third-party JS до твоего кода. Ничего из этого не появляется в bundle analyzer — файлы грузятся с внешних доменов во время выполнения. Ничего из этого нельзя tree-shaken — ты не контролируешь источник. И большинство работает на main thread, блокируя paint и взаимодействие.

Проблема усугубляется: бизнес-команды часто добавляют скрипты через Google Tag Manager без инженерного review. Каждое добавление через tag manager обходит code review полностью.

Паттерн 1: Interaction gating

Грузи скрипт только когда юзер делает действие, требующее его. Chat widget грузится при клике «Help». Analytics SDK грузится после первого значимого взаимодействия. Newsletter modal скрипт грузится когда юзер проскроллил до 80% страницы.

<!-- Defer до клика -->
<button id="chat-btn">Chat with us</button>
<script>
  document.getElementById('chat-btn').addEventListener('click', () => {
    const script = document.createElement('script');
    script.src = 'https://widget.intercom.io/widget/APP_ID';
    document.body.appendChild(script);
  });
</script>

Tradeoff: первое взаимодействие, триггерящее загрузку, имеет видимую задержку пока chunk скачивается и парсится. Смягчи через prefetch когда trigger-элемент становится видимым (IntersectionObserver на кнопке) или на mouseenter.

Паттерн 2: Web Worker изоляция через PartyTown

PartyTown — open-source библиотека (Builder.io), запускающая third-party скрипты в Web Worker через service-worker прокси. DOM-доступ из Worker bridged через synchronous postMessage. Main thread освобождается от analytics, ad и tracking скриптов полностью.

<script>
  partytown = { forward: ['dataLayer.push', 'fbq', 'gtag'] };
</script>
<script src="/~partytown/partytown.js"></script>
<script type="text/partytown" src="https://www.googletagmanager.com/gtm.js?id=GTM-XXXX"></script>

Tradeoff: скрипты, зависящие от синхронного DOM-доступа, несовместимы (редко для analytics). postMessage round-trips добавляют ~5-15 мс per call. Некоторые скрипты ломаются при проксировании. Тестируй каждого vendor перед деплоем.

Паттерн 3: Server-side measurement

Перенеси analytics events на сервер. Вместо того чтобы шить 150 КБ Segment-клиент каждому юзеру, firing Segment events из твоего API-сервера на нужных действиях. Юзеры получают tracking; браузеры не получают ничего.

Похожие варианты: Google Analytics Measurement Protocol, Sentry server-side error capture для SSR ошибок, кастомный event pipeline через лёгкий beacon endpoint.

Tradeoff: теряешь browser-only контекст — user agent details, real-time client errors, click heatmaps. Подходит для core funnel analytics; комбинируй с лёгким client SDK для browser-специфических сигналов.

ПаттернMain-thread стоимостьTradeoff
Interaction gatingНоль до триггераFirst-use latency; смягчить prefetch
PartyTown Web WorkerПочти ноль (проксировано в Worker)DOM-sync несовместимые скрипты; postMessage overhead
Server-side measurementНоль (ничего на клиенте)Теряется browser-специфический контекст

Governance: отдельный third-party бюджет

Senior-команды ведут отдельный third-party бюджет наряду с app bundle бюджетом. Конкретно: файл third-party-budget.json в репо, перечисляющий каждый разрешённый third-party домен, его approved размер и команду-owner. Любой новый скрипт через GTM или <script src>, которого нет в файле, fail’ит CI.

Дополнительный enforcement: CSP (Content Security Policy) заголовок script-src перечисляет разрешённые origins. Скрипты с не перечисленных origins блокируются браузером. Ежеквартальный аудит просматривает каждую запись, удаляет unused vendors и проверяет track records.

Почему это работает

Почему third-party scripts непропорционально вредят? (1) Vendor’ы ставят features выше байтов — chat SDK поддерживает каждый use case, даже если app использует 5%. (2) Нет tree shaking — нельзя убрать unused vendor код. (3) Кумулятивный эффект — 10 скриптов по 100 КБ = 1 МБ до твоего кода. (4) Main-thread блокировка — большинство запускается синхронно при загрузке страницы если явно не деferred.

Викторина

Маркетинг хочет 200 КБ chat widget на каждой странице и говорит: должен грузиться немедленно. Senior-компромисс?

Викторина

Команда запускает пять analytics скриптов через GTM суммарно 600 КБ. Они мигрируют funnel events на server-side Measurement Protocol. Какой ожидаемый клиентский эффект?

Викторина

Почему CSP заголовок script-src релевантен для third-party budget governance?

Вспомните перед уходом
  1. 01
    Почему third-party scripts непропорционально раздувают bundle-стоимость по сравнению с first-party кодом?
  2. 02
    Опиши паттерн interaction gating и его tradeoff.
Итог

Third-party scripts регулярно добавляют 500 КБ-1 МБ на каждую страницу, вне app репо и вне code review. Три структурных countermeasure: interaction gating (грузить при триггере, ноль initial-стоимости), PartyTown Web Worker изоляция (main thread освобождён), server-side measurement (ничего на клиенте). Governance через third-party budget file и CSP enforce’ит allow-list в CI и на уровне браузера. Следующий урок рассматривает CI enforcement: как сделать бюджет жёстким constraint, а не руководством.

Связанные уроки
встречается в159
Продолжить восхождение ↑CI enforcement и RUM: делаем бюджеты рабочими
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.