Вы пишете npm-библиотеку, которая должна работать одновременно в браузере и Node.js. В каком-то месте нужно добавить полифил, если браузер его не поддерживает. Для этого нужно знать, где найти глобальный контекст и как безопасно проверить наличие API.
JavaScript выполняется в разных средах, и у каждой — свой глобальный объект. Раньше код приходилось писать по-разному для браузера и Node.js. globalThis — стандартный способ обратиться к глобальному объекту в любой среде.
var, let, const и глобальной областью| Среда | Глобальный объект |
|-------|-------------------|
| Браузер | window |
| Node.js | global |
| Web Worker | self |
| Универсально | globalThis |
// globalThis работает везде — в браузере, Node.js, Web Workers
console.log(typeof globalThis) // 'object' — всегда
// В браузере: globalThis === window → true
// В Node.js: globalThis === global → truevar appName = 'MyShop'
console.log(globalThis.appName) // 'MyShop' (в браузере: window.appName)
// let и const — НЕ попадают в globalThis
let version = '2.0'
console.log(globalThis.version) // undefinedЭто плохая практика: переменная с именем name или length случайно перезапишет встроенное свойство window.
// НЕПРАВИЛЬНО — в Node.js выбросит ReferenceError:
if (window !== undefined) { ... }
// ПРАВИЛЬНО — typeof не бросает ошибку для необъявленных переменных:
if (typeof window !== 'undefined') {
// Мы в браузере
console.log('Браузер, начинаем рендеринг')
} else {
// Мы в Node.js или другой среде
console.log('Серверная среда, SSR режим')
}Или используйте globalThis — проверяйте через него без риска:
const isBrowser = typeof globalThis.document !== 'undefined'
const isNode = typeof globalThis.process !== 'undefined'Полифил добавляет новый API в старые среды через глобальный объект:
// Добавляем структурированный полифил для structuredClone
if (typeof globalThis.structuredClone === 'undefined') {
globalThis.structuredClone = function(obj) {
return JSON.parse(JSON.stringify(obj)) // упрощённый вариант
}
}
// Теперь structuredClone работает везде
const copy = structuredClone({ a: 1, b: [2, 3] })Ошибка 1: прямое обращение к window в Node.js
// Сломано в Node.js — ReferenceError: window is not defined
if (window.innerWidth < 768) {
loadMobileLayout()
}
// Исправлено:
if (typeof globalThis.window !== 'undefined' && window.innerWidth < 768) {
loadMobileLayout()
}Ошибка 2: глобальная переменная вместо модуля
// Плохо: любой код может случайно изменить состояние
var currentUser = null
// Хорошо: модульное состояние — только один файл управляет им
// user-store.js
let _currentUser = null
export const setUser = (user) => { _currentUser = user }
export const getUser = () => _currentUserОшибка 3: feature detection по строке User-Agent вместо проверки свойства
// Плохо: ненадёжно, легко сломать
const isChrome = navigator.userAgent.includes('Chrome')
// Хорошо: проверяем наличие конкретного API
const supportsWebP = typeof globalThis.createImageBitmap !== 'undefined'
const supportsStorage = typeof globalThis.localStorage !== 'undefined'globalThis позволяет одному коду работать на сервере (Next.js SSR) и в браузере без if/else на каждый чихcore-js и подобные библиотеки добавляют API в globalThis для старых браузеровglobalThis — это jsdom-окружение; через него мокируют fetch и другие APIglobalThis.APP_CONFIG = {...} — антипаттерн; лучше использовать переменные окружения через process.env или import.meta.envFeature detection, полифил и безопасная проверка среды через globalThis
// 1. globalThis — универсальный доступ к глобальному объекту
console.log(typeof globalThis) // 'object'
console.log(typeof globalThis.Array) // 'function' — встроенные всегда есть
console.log(typeof globalThis.Promise) // 'function'
// 2. Feature detection — проверяем конкретный API, не среду
function checkEnvironmentFeatures() {
const checks = {
fetch: typeof globalThis.fetch !== 'undefined',
Promise: typeof globalThis.Promise !== 'undefined',
structuredClone: typeof globalThis.structuredClone !== 'undefined',
WebSocket: typeof globalThis.WebSocket !== 'undefined',
localStorage: typeof globalThis.localStorage !== 'undefined',
IntersectionObserver:typeof globalThis.IntersectionObserver!== 'undefined',
}
console.log('=== Поддержка API ===')
for (const [api, supported] of Object.entries(checks)) {
const mark = supported ? 'есть' : 'нет'
console.log(` ${api.padEnd(22)}: ${mark}`)
}
return checks
}
checkEnvironmentFeatures()
// 3. Полифил через globalThis — добавляем если нет
if (typeof globalThis.structuredClone === 'undefined') {
globalThis.structuredClone = function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj
return JSON.parse(JSON.stringify(obj))
}
console.log('\nПолифил structuredClone установлен')
} else {
console.log('\nstructuredClone уже доступен нативно')
}
const original = { name: 'Алиса', scores: [95, 87, 92] }
const clone = structuredClone(original)
clone.scores.push(100)
console.log('Оригинал scores:', original.scores) // [95, 87, 92]
console.log('Клон scores: ', clone.scores) // [95, 87, 92, 100]
// 4. Определение среды — безопасно через typeof
const env = {
isBrowser: typeof globalThis.document !== 'undefined',
isNode: typeof globalThis.process !== 'undefined' && !!globalThis.process.versions?.node,
isWorker: typeof globalThis.WorkerGlobalScope !== 'undefined',
}
console.log('\n=== Среда выполнения ===')
console.log('Браузер:', env.isBrowser)
console.log('Node.js:', env.isNode)
console.log('Worker: ', env.isWorker)Вы пишете npm-библиотеку, которая должна работать одновременно в браузере и Node.js. В каком-то месте нужно добавить полифил, если браузер его не поддерживает. Для этого нужно знать, где найти глобальный контекст и как безопасно проверить наличие API.
JavaScript выполняется в разных средах, и у каждой — свой глобальный объект. Раньше код приходилось писать по-разному для браузера и Node.js. globalThis — стандартный способ обратиться к глобальному объекту в любой среде.
var, let, const и глобальной областью| Среда | Глобальный объект |
|-------|-------------------|
| Браузер | window |
| Node.js | global |
| Web Worker | self |
| Универсально | globalThis |
// globalThis работает везде — в браузере, Node.js, Web Workers
console.log(typeof globalThis) // 'object' — всегда
// В браузере: globalThis === window → true
// В Node.js: globalThis === global → truevar appName = 'MyShop'
console.log(globalThis.appName) // 'MyShop' (в браузере: window.appName)
// let и const — НЕ попадают в globalThis
let version = '2.0'
console.log(globalThis.version) // undefinedЭто плохая практика: переменная с именем name или length случайно перезапишет встроенное свойство window.
// НЕПРАВИЛЬНО — в Node.js выбросит ReferenceError:
if (window !== undefined) { ... }
// ПРАВИЛЬНО — typeof не бросает ошибку для необъявленных переменных:
if (typeof window !== 'undefined') {
// Мы в браузере
console.log('Браузер, начинаем рендеринг')
} else {
// Мы в Node.js или другой среде
console.log('Серверная среда, SSR режим')
}Или используйте globalThis — проверяйте через него без риска:
const isBrowser = typeof globalThis.document !== 'undefined'
const isNode = typeof globalThis.process !== 'undefined'Полифил добавляет новый API в старые среды через глобальный объект:
// Добавляем структурированный полифил для structuredClone
if (typeof globalThis.structuredClone === 'undefined') {
globalThis.structuredClone = function(obj) {
return JSON.parse(JSON.stringify(obj)) // упрощённый вариант
}
}
// Теперь structuredClone работает везде
const copy = structuredClone({ a: 1, b: [2, 3] })Ошибка 1: прямое обращение к window в Node.js
// Сломано в Node.js — ReferenceError: window is not defined
if (window.innerWidth < 768) {
loadMobileLayout()
}
// Исправлено:
if (typeof globalThis.window !== 'undefined' && window.innerWidth < 768) {
loadMobileLayout()
}Ошибка 2: глобальная переменная вместо модуля
// Плохо: любой код может случайно изменить состояние
var currentUser = null
// Хорошо: модульное состояние — только один файл управляет им
// user-store.js
let _currentUser = null
export const setUser = (user) => { _currentUser = user }
export const getUser = () => _currentUserОшибка 3: feature detection по строке User-Agent вместо проверки свойства
// Плохо: ненадёжно, легко сломать
const isChrome = navigator.userAgent.includes('Chrome')
// Хорошо: проверяем наличие конкретного API
const supportsWebP = typeof globalThis.createImageBitmap !== 'undefined'
const supportsStorage = typeof globalThis.localStorage !== 'undefined'globalThis позволяет одному коду работать на сервере (Next.js SSR) и в браузере без if/else на каждый чихcore-js и подобные библиотеки добавляют API в globalThis для старых браузеровglobalThis — это jsdom-окружение; через него мокируют fetch и другие APIglobalThis.APP_CONFIG = {...} — антипаттерн; лучше использовать переменные окружения через process.env или import.meta.envFeature detection, полифил и безопасная проверка среды через globalThis
// 1. globalThis — универсальный доступ к глобальному объекту
console.log(typeof globalThis) // 'object'
console.log(typeof globalThis.Array) // 'function' — встроенные всегда есть
console.log(typeof globalThis.Promise) // 'function'
// 2. Feature detection — проверяем конкретный API, не среду
function checkEnvironmentFeatures() {
const checks = {
fetch: typeof globalThis.fetch !== 'undefined',
Promise: typeof globalThis.Promise !== 'undefined',
structuredClone: typeof globalThis.structuredClone !== 'undefined',
WebSocket: typeof globalThis.WebSocket !== 'undefined',
localStorage: typeof globalThis.localStorage !== 'undefined',
IntersectionObserver:typeof globalThis.IntersectionObserver!== 'undefined',
}
console.log('=== Поддержка API ===')
for (const [api, supported] of Object.entries(checks)) {
const mark = supported ? 'есть' : 'нет'
console.log(` ${api.padEnd(22)}: ${mark}`)
}
return checks
}
checkEnvironmentFeatures()
// 3. Полифил через globalThis — добавляем если нет
if (typeof globalThis.structuredClone === 'undefined') {
globalThis.structuredClone = function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj
return JSON.parse(JSON.stringify(obj))
}
console.log('\nПолифил structuredClone установлен')
} else {
console.log('\nstructuredClone уже доступен нативно')
}
const original = { name: 'Алиса', scores: [95, 87, 92] }
const clone = structuredClone(original)
clone.scores.push(100)
console.log('Оригинал scores:', original.scores) // [95, 87, 92]
console.log('Клон scores: ', clone.scores) // [95, 87, 92, 100]
// 4. Определение среды — безопасно через typeof
const env = {
isBrowser: typeof globalThis.document !== 'undefined',
isNode: typeof globalThis.process !== 'undefined' && !!globalThis.process.versions?.node,
isWorker: typeof globalThis.WorkerGlobalScope !== 'undefined',
}
console.log('\n=== Среда выполнения ===')
console.log('Браузер:', env.isBrowser)
console.log('Node.js:', env.isNode)
console.log('Worker: ', env.isWorker)Напиши функцию isSupported(featureName), которая проверяет, существует ли в глобальном окружении свойство с таким именем. Функция должна возвращать true или false, не бросая ошибок.
return typeof globalThis[featureName] !== 'undefined'