Skip to content

Справочник ​

Архитектура ​

responsive-media
│
├── BaseResponsiveState  (абстрактный)
│     Прокси над обычным Record<string, boolean>
│     Пакетные обновления — все колбэки matchMedia/ResizeObserver собираются
│     перед тем, как срабатывает единый notify()
│     Реестр подписок: глобальные слушатели + слушатели по конкретному ключу
│     Debounce для subscribe(); слушатели по ключу никогда не дебаунсятся
│     Упорядоченные хелперы брейкпоинтов: current / isAbove / isBelow / between
│     Утилиты: syncCSSVars / emitDOMEvents / toSignal / hydrate / destroy
│
├── ReactiveResponsiveState  extends BaseResponsiveState
│     setupSources()  → window.matchMedia на каждый ключ конфига
│     Сгенерированная строка media query хранится в карте mediaQueries
│     Пакетирует все события 'change' MediaQueryList, затем сбрасывает
│     setConfig() / destroy() cleanupSources() удаляет обработчики matchMedia
│
├── ContainerState  extends BaseResponsiveState
│     setupSources()  → единственный ResizeObserver на целевом элементе
│     Вычисляет условия width/height/orientation/aspect-ratio в JS
│     Переподключает observer при изменении конфига; teardown в destroy()
│
├── createResponsiveState(config, options)
│     Фабрика — возвращает новый экземпляр ReactiveResponsiveState
│
├── responsiveState  (глобальный синглтон)
│     Предварительно настроен с ResponsiveConfig по умолчанию (mobile/tablet/desktop)
│     setResponsiveConfig() / getResponsiveState() / getResponsiveMediaQueries()
│     делегируют этому экземпляру
│
├── toMediaQueryString(conditions)
│     Конвертирует MediaQueryConfig → CSS-строку
│     AND: плоский массив → объединяется через ' and '
│     OR:  вложенный массив → группы объединяются через ', '
│     Числовые значения получают суффикс 'px' (кроме raw / orientation / …)
│
├── match(state, map, fallback?)
│     Поиск первого совпадения — возвращает сопоставленное значение для первого истинного ключа в map
│
├── subscribeMediaQuery(query, callback)
│     Тонкая обёртка вокруг window.matchMedia + addEventListener('change')
│     Возвращает функцию очистки
│
├── Адаптер Vue  (vue-responsive.ts)
│     RESPONSIVE_KEY    — ключ инъекции; provide() его, чтобы передать useResponsive()/
│                          useBreakpoints() кастомное состояние вместо глобального
│     ResponsivePlugin  — app.use(); вызывает setResponsiveConfig, делает provide() RESPONSIVE_KEY
│     useResponsive()   — сначала inject(RESPONSIVE_KEY), иначе shallowReactive-зеркало; subscribe() синхронизирует его
│     useBreakpoints()  — возвращает { current, isAbove, isBelow, between }
│                          тоже сначала проверяет inject(RESPONSIVE_KEY), как и useResponsive()
│     useMediaQuery()   — оборачивает subscribeMediaQuery в ref + onUnmounted; возвращаемая ссылка
│                          также всегда несёт .stop() для очистки вне экземпляра компонента
│     useContainerState() — watchEffect над templateRef; создаёт/уничтожает
│                           ContainerState; возвращает shallowReactive-зеркало
│
├── Адаптер React  (react-responsive.ts)
│     useResponsive()     — useSyncExternalStore(subscribe, getState, getState)
│     useBreakpoints()    — useSyncExternalStore + оборачивает упорядоченные хелперы
│     useMediaQuery()     — useSyncExternalStore над subscribeMediaQuery
│     useContainerState() — useEffect создаёт ContainerState; useState-зеркало;
│                           повторяет попытку через requestAnimationFrame, если ref ещё не подключён
│
└── Пресеты  (presets.ts)
      ResponsiveConfig     — mobile/tablet/desktop по умолчанию
      TailwindPreset / TailwindOrder
      BootstrapPreset / BootstrapOrder
      AccessibilityPreset

Размер бандла и peer-зависимости ​

Точка входаPeer-зависимостиРазмер (мин. + gzip)Заметки
responsive-media(нет)12,5 кБ + 4,3 кБТолько framework-agnostic ядро — без кода Vue или React
responsive-media/vuevue ^3.5.2712,0 кБ + 4,2 кБТолько Vue composables
responsive-media/reactreact ^1910,3 кБ + 3,5 кБТолько React-хуки
responsive-media/presets(нет)1,3 кБ + 0,4 кБТолько конфиги пресетов — добавляются в любой экземпляр
responsive-media/container(нет)6,8 кБ + 2,4 кБТолько класс ContainerState + фабрика
responsive-media/nuxt@nuxt/kit0 в браузереМодуль Nuxt — только на этапе сборки, без кода для браузера
responsive-media/testing(нет)3,8 кБ + 1,7 кБПомощники для тестов — управляемый matchMedia

Размеры даны для всей точки входа, минифицированной и сжатой gzip, без Vue, React и @nuxt/kit; измерены на 2.2.2 (npm run size в репозитории пакета повторяет измерение). Каждая точка входа несёт в себе ядро, которым пользуется, поэтому размеры не складываются: приложение, использующее точку входа Vue, платит за неё один раз, а не ещё и за корневую.

Типичные импорты ​

ИмпортРазмер (мин. + gzip)
createResponsiveState из корня6,2 кБ + 2,1 кБ
useResponsive из responsive-media/vue6,8 кБ + 2,4 кБ
useMediaQuery из responsive-media/vue0,6 кБ + 0,4 кБ
defineResponsive из responsive-media/vue8,5 кБ + 3,1 кБ
useResponsive из responsive-media/react6,4 кБ + 2,2 кБ

Пакет помечен sideEffects: false, а общее responsiveState живёт в отдельном модуле, поэтому сборщик отбрасывает его, если его никто не импортирует. Поэтому useMediaQuery, которому общее состояние не нужно, весит малую долю полной точки входа; функции, построенные на состоянии, например useResponsive, по-прежнему несут его с собой.

Пакет поставляется как tree-shakeable ESM и CommonJS. Начиная с 2.0, адаптер Vue (ResponsivePlugin, useResponsive и т. д.) имеет собственную точку входа responsive-media/vue — точно так же, как и React-адаптер. Основная точка входа больше не импортирует ничего специфичного для Vue или React, так что её вес остаётся минимальным для любого потребителя, с фреймворком или без. (До 2.0 адаптер Vue был встроен в основную точку входа, из-за чего сам факт импорта корня пакета тянул статический импорт @vue/runtime-core — это была реальная ошибка, а не задокументированное поведение tree-shaking; если вам встретится старый пример кода, импортирующий Vue composables из голого 'responsive-media', поправьте его на 'responsive-media/vue'.)

Лицензия ​

MIT