Анализ размера бандла

TanStack Query построена как модульная библиотека с упором на tree-shaking и разбиение функциональности по уровням абстракции. Размер итогового бандла определяется не только самой библиотекой, но и способом её интеграции в приложение, типом сборщика и структурой импортов.

Основные источники веса в продакшн-бандле:

  • ядро запросов (query core)
  • React-интеграция (или адаптер под другой фреймворк)
  • DevTools (часто случайно попадают в продакшн)
  • неэффективные импорты (barrel imports, deep imports)
  • дублирование зависимостей из-за неправильного tree-shaking

Архитектура пакетов и влияние на сборку

Современная версия TanStack Query разделена на несколько логических слоёв:

  • @tanstack/query-core — минимальное ядро
  • @tanstack/react-query — React-обёртка
  • дополнительные пакеты (DevTools, persist-client и др.)

Такое разделение позволяет сборщику удалять неиспользуемые части, если проект использует ESM-сборку.

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


Tree-shaking как основной механизм оптимизации

Tree-shaking работает эффективно только при соблюдении нескольких условий:

  • используется ESM (import/export)
  • сборщик поддерживает статический анализ (Vite, Rollup, esbuild, Webpack production mode)
  • отсутствуют побочные эффекты в модулях

TanStack Query проектируется с минимальными side effects, что позволяет удалять неиспользуемые части API.

Однако типичная ошибка — импорт из корня пакета без контроля:

import * as Query from "@tanstack/react-query";

Такой подход почти всегда приводит к включению всего пакета.


Влияние импортов на размер бандла

Неблагоприятные паттерны

Barrel imports:

import { useQuery, QueryClient } from "@tanstack/react-query";

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

Deep imports (в старых версиях или внутренних API):

import { QueryClient } from "@tanstack/query-core/dist/queryClient";

Такие импорты ломают гарантии стабильности и могут обходить оптимизации.


Оптимальные паттерны

Стандартный импорт из публичного API:

import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";

В современных сборках это оптимальный вариант, так как:

  • сохраняется tree-shaking
  • используется публичный контракт пакета
  • исключаются внутренние зависимости

DevTools и их влияние

DevTools — один из частых источников неожиданного роста бандла.

import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

Если этот импорт не обёрнут условием окружения, он попадёт в production-сборку.

Типичная ошибка:

<ReactQueryDevtools initialIsOpen={false} />

без проверки окружения.

Оптимальный подход — разделение по окружению сборки, чтобы DevTools полностью исключались из production chunk.


QueryClient как точка роста зависимостей

QueryClient является центральным объектом управления состоянием кеша.

Он включает:

  • менеджер запросов
  • кеш-слой
  • систему подписок
  • garbage collection логики

Хотя сам по себе он не тяжёлый, он тянет query-core, который содержит основную логику.

Важно учитывать:

  • создание нескольких QueryClient не увеличивает бандл
  • увеличение веса происходит только при импорте дополнительных модулей

Разделение кода (code splitting)

TanStack Query хорошо сочетается с динамическими импортами:

const { useQuery } = await import("@tanstack/react-query");

Такой подход позволяет:

  • вынести редко используемые страницы
  • отделить административные панели
  • минимизировать initial bundle

Особенно эффективно в SPA с маршрутизацией по страницам.


Влияние сборщика

Vite / esbuild

  • минимальный overhead
  • агрессивный tree-shaking
  • корректная работа с ESM

Webpack

  • зависит от режима production
  • требует настройки sideEffects: false
  • чувствителен к barrel imports

Rollup

  • наиболее предсказуемый tree-shaking
  • часто используется в библиотеках TanStack

Методы анализа размера бандла

Webpack Bundle Analyzer

Позволяет визуально определить:

  • какие части TanStack Query попали в финальный бандл
  • наличие дубликатов
  • неиспользуемые модули

Source Map Explorer

Полезен для Vite-сборок:

  • анализирует итоговый dist bundle
  • показывает вклад каждого модуля

BundlePhobia

Используется для быстрой оценки:

  • gzip и brotli размер пакета
  • сравнение версий

Частые причины увеличения размера

Импорт всего пакета

import * as ReactQuery from "@tanstack/react-query";

Результат: отключение tree-shaking.


Подключение DevTools в production

Даже если компонент не используется, импорт может попасть в бандл.


Неправильная структура barrel файлов

Если приложение повторно экспортирует TanStack Query через собственные index.ts:

export * from "@tanstack/react-query";

это усложняет статический анализ.


Дублирование React Query в монорепозиториях

В монорепо часто возникает ситуация:

  • несколько версий @tanstack/react-query
  • разные зависимости в пакетах

Это увеличивает итоговый bundle без видимых причин.


Стратегии минимизации размера

Явные импорты

import { useQuery } from "@tanstack/react-query";

без namespace импортов.


Исключение DevTools из production

{process.env.NODE_ENV !== "production" && (
  <ReactQueryDevtools />
)}

Контроль зависимостей в монорепо

  • фиксация версии через lockfile
  • дедупликация зависимостей
  • проверка npm ls @tanstack/react-query

Разделение клиентской логики

  • QueryClient в отдельном модуле
  • lazy-loading провайдеров
  • изоляция query-логики по доменам

Эффект версий и миграций

Переход между major-версиями TanStack Query может влиять на размер:

  • удаление устаревших API снижает вес
  • добавление новых адаптеров увеличивает поверхность API
  • изменение структуры экспорта влияет на tree-shaking

Особенно важно учитывать переход на scoped пакеты (@tanstack/*), где изменена модульная структура.


Практическая модель оценки бандла

Оценка веса TanStack Query в приложении обычно сводится к трём слоям:

  1. базовый runtime (query-core)
  2. адаптер фреймворка (React/Vue/Solid)
  3. дополнительные инструменты (DevTools, persist, optimistic utils)

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