Справочник
Архитектура
os-detect
│
├── src/utils/platform.ts
│ getUADataPlatform() → navigator.userAgentData.platform (Chrome/Edge)
│ isNodeNavigator() → отличает собственный синтетический navigator
│ Node.js (Node 21+) от настоящего браузерного navigator
│ getNodePlatform() → process.platform (только Node.js)
│
├── src/utils/cache.ts
│ memoizeBoolean() → оборачивает синхронный детектор одноразовым кэшем
│ memoizeAsyncBoolean() → то же самое для асинхронной detectIsWindows11();
│ также делит один промис "в полёте" между
│ параллельными вызовами до его разрешения
│ resetDetectionCache() → очищает каждый кэш, зарегистрированный любым из хелперов
│
├── src/detectors/ios.ts detectIsIOS() → UA + maxTouchPoints (учитывает iPadOS 13+)
├── src/detectors/macos.ts detectIsMacOS() → UAData / UA / process.platform=darwin
├── src/detectors/android.ts detectIsAndroid() → UAData / UA / process.platform=android
├── src/detectors/chromeos.ts detectIsChromeOS() → UAData / UA (только браузер)
├── src/detectors/linux.ts detectIsLinux() → UAData / UA / process.platform=linux
│ (исключает Android и ChromeOS)
├── src/detectors/windows.ts detectIsWindows() → UAData / UA / process.platform=win32
│ detectIsWindows11() → асинхронно, кэшируется через memoizeAsyncBoolean()
│ браузер: userAgentData.getHighEntropyValues(['platformVersion'])
│ platformVersion >= 13.0.0 → Windows 11
│ Node.js: import('os').release() номер сборки >= 22000
│
├── src/detectors/touch.ts detectHasTouch() → maxTouchPoints / msMaxTouchPoints / ontouchstart
├── src/detectors/tv.ts detectIsTV() → UAData platform='tv' / UA (Tizen, webOS и т. д.)
├── src/detectors/node.ts detectIsNode() → process.versions.node
├── src/detectors/browser.ts detectIsBrowser() → typeof window/document !== 'undefined'
├── src/detectors/webworker.ts detectIsWebWorker() → self && !window && importScripts
├── src/detectors/electron.ts detectIsElectron() → process.versions.electron / UA 'Electron/'
├── src/detectors/pwa.ts detectIsPWA() → matchMedia display-mode / navigator.standalone
│ / referrer android-app://
│
├── src/index.ts (базовая точка входа — реэкспортирует детекторы выше, плюс:)
│ getOS() → вызывает детекторы в порядке приоритета
│ isMobileDevice() → detectIsIOS() || detectIsAndroid()
│ isDesktopDevice() → detectIsMacOS() || detectIsWindows()
│ || detectIsLinux() || detectIsChromeOS()
│ getFormFactor() → detectIsTV() / ОС + размеры экрана
│ getRuntime() → detectIsWebWorker() → detectIsBrowser() → detectIsNode()
│ getPrimaryInput() → matchMedia('(pointer: …)'), НЕ кэшируется
│ getPixelRatio() → window.devicePixelRatio, НЕ кэшируется
│ detectIsiOS() → устаревший алиас для detectIsIOS()
│
├── src/react.ts (os-detect/react)
│ useOS() → useState(() => getOS())
│ useIsWindows11() → useState(null) + useEffect → detectIsWindows11()
│ useFormFactor() → useState(() => getFormFactor())
│ useRuntime() → useState(() => getRuntime())
│ usePrimaryInput() → useState('unknown') + useEffect → слушатели matchMedia
│
└── src/vue.ts (os-detect/vue)
useOS() → readonly(ref(getOS()))
useIsWindows11() → readonly(ref(null)) + onMounted → detectIsWindows11()
useFormFactor() → readonly(ref(getFormFactor()))
useRuntime() → readonly(ref(getRuntime()))
usePrimaryInput() → readonly(ref('unknown')) + onMounted/onUnmounted →
слушатели matchMediaСовместимость с SSR
Базовая точка входа безопасна для вызова во время серверного рендеринга — определение Node.js читает process.platform напрямую (в том числе на Node.js 21+, где собственный синтетический глобал navigator рантайма корректно распознаётся и не перекрывает Node.js-путь).
За чем стоит следить SSR-фреймворкам — это несовпадения при гидратации, а не ошибочное определение Node.js: getOS() во время серверного рендеринга возвращает ОС сервера, которая может отличаться от клиентской. Любой UI, зависящий от getOS()/useOS(), стоит откладывать до клиента, если требуется точное совпадение — точный паттерн см. в разделах SSR для React-хуков и Composables для Vue. detectIsWindows11()/useIsWindows11() это не затрагивает — они асинхронны и разрешаются только на клиенте.
Функции, требующие настоящего браузерного окружения (detectIsIOS(), detectIsChromeOS(), detectHasTouch(), detectIsTV(), detectIsPWA()), в Node.js всегда возвращают false — там нет ни userAgent, ни maxTouchPoints, ни matchMedia для чтения. getFormFactor() и getRuntime() в Node.js всё же разрешаются в реальное значение ('unknown' и 'node' соответственно, в обычном скрипте), поскольку не для каждой ветки зависят от браузерных глобалов.
getPrimaryInput() и getPixelRatio() — два исключения из «всё кэшируется» выше — почему именно, см. Как это работает, а заметки о SSR во Vue описывают ту же ловушку с гидратацией, что уже есть у useOS() — и её же несут useFormFactor()/useRuntime().
Размер бандла и peer-зависимости
| Точка входа | Peer-зависимости | Формат | Заметки |
|---|---|---|---|
os-detect | — | ESM, CJS, UMD | Базовая часть — все функции определения и типы OS/FormFactor/Runtime/PrimaryInput |
os-detect/react | react >=17 | ESM, CJS | Хуки useOS, useIsWindows11, useFormFactor, useRuntime, usePrimaryInput |
os-detect/vue | vue >=3 | ESM, CJS | Те же пять, как composables |
Все три точки входа перечислены в exports пакета package.json, у каждой есть собственный настоящий .d.ts. Адаптеры для React и Vue не добавляют никакой рантайм-логики сверх самих хуков/composables — они вызывают те же кэшируемые базовые функции.
У пакета нулевые runtime-зависимости. React и Vue — опциональные peer-зависимости, они нужны только при использовании соответствующей точки входа.
Миграция
detectIsiOS() переименована в detectIsIOS() (заглавная OS) для согласованности с остальным API.
Старое имя всё ещё работает в v2, но выводит предупреждение об устаревании (один раз за сессию, начиная с v2.2.1) и будет удалено в v3.0:
detectIsiOS() // ⚠ устарело — выводит console.warn один раз за сессию
detectIsIOS() // ✓ используйте это вместоДругих breaking-изменений между v1 и v2 нет.
Лицензия
MIT