Browserslist и целевые браузеры

Browserslist — это механизм описания списка браузеров и их версий, которые должны поддерживаться проектом. Он используется не только в Webpack, но и во множестве инструментов экосистемы Jav * aScript:

  • Babel
  • Autoprefixer
  • PostCSS
  • ESLint
  • Stylelint
  • SWC
  • Parcel
  • Vite
  • Rollup
  • TypeScript-инструменты
  • CSS-минификаторы

Webpack напрямую не транспилирует код под браузеры, однако он тесно интегрируется с Babel и другими инструментами, использующими Browserslist. Благодаря этому появляется единый источник правды для определения поддерживаемых платформ.


Проблема совместимости браузеров

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

  • Promise
  • async/await
  • optional chaining (?.)
  • nullish coalescing (??)
  • private fields
  • ES Modules
  • CSS Grid
  • flex gap
  • logical properties
  • dynamic import

Если отправить современный код старому браузеру без обработки, приложение может полностью перестать работать.

Пример несовместимого кода:

const user = response?.data?.user ?? {};

Старые версии браузеров не понимают:

  • optional chaining
  • nullish coalescing

В результате возникает синтаксическая ошибка ещё до выполнения приложения.


Роль Browserslist в Webpack

Webpack обычно работает совместно с:

  • babel-loader
  • @babel/preset-env
  • postcss-loader
  • autoprefixer

Все эти инструменты ориентируются на Browserslist для определения:

  • какие возможности JavaScript нужно транспилировать;
  • какие CSS-префиксы добавлять;
  • какие полифилы подключать;
  • какие оптимизации допустимы;
  • какие синтаксические конструкции можно оставить без изменений.

Где задаётся Browserslist

В package.json

Наиболее распространённый способ:

{
  "browserslist": [
    "> 0.5%",
    "last 2 versions",
    "not dead"
  ]
}

В отдельном файле .browserslistrc

> 0.5%
last 2 versions
not dead

В нескольких окружениях

[production]
> 0.5%
last 2 versions
not dead

[development]
last 1 chrome version
last 1 firefox version
last 1 safari version

Это позволяет:

  • ускорять сборку в development;
  • использовать минимальную транспиляцию при разработке;
  • обеспечивать совместимость в production.

Как работает @babel/preset-env

@babel/preset-env анализирует список браузеров и определяет:

  • какие преобразования нужны;
  • какие синтаксические конструкции поддерживаются;
  • какие полифилы подключать.

Пример конфигурации Babel:

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage',
        corejs: 3
      }
    ]
  ]
};

Что означает useBuiltIns: 'usage'

Режим usage автоматически подключает только необходимые полифилы.

Например:

Promise.resolve();

Если целевой браузер не поддерживает Promise, Babel автоматически подключит нужный полифил.

Без Browserslist Babel не сможет определить, нужен ли этот полифил.


Популярные запросы Browserslist

Поддержка популярных браузеров

> 1%

Поддерживаются браузеры с долей рынка выше 1%.


Последние версии браузеров

last 2 versions

Поддерживаются две последние версии каждого браузера.


Исключение устаревших браузеров

not dead

Исключаются браузеры:

  • без обновлений более 24 месяцев;
  • официально прекращённые;
  • имеющие менее 0.5% пользователей.

Исключение Internet Explorer

not IE 11

Поддержка конкретного браузера

Chrome >= 90

Только современные браузеры

supports es6-module

Комбинирование условий

Browserslist поддерживает логические комбинации.

Пример:

> 0.5%
last 2 versions
not dead
not IE 11

Development и Production окружения

Разные цели сборки требуют разной совместимости.

Development

Во время разработки обычно используются современные браузеры.

Пример:

[development]
last 1 chrome version

Преимущества:

  • быстрая сборка;
  • меньше транспиляции;
  • проще source maps;
  • меньше размер bundle.

Production

В production необходима совместимость.

Пример:

[production]
> 0.5%
not dead

Проверка итогового списка браузеров

Команда:

npx browserslist

Показывает итоговый список браузеров.

Пример вывода:

chrome 124
chrome 123
firefox 125
safari 17.4

Проверка конкретного запроса

npx browserslist "> 1%"

Обновление базы данных browserslist

Browserslist использует базу caniuse-lite.

Со временем данные устаревают.

Обновление:

npx update-browserslist-db@latest

или:

npm update caniuse-lite browserslist

Интеграция с Autoprefixer

Browserslist активно используется для CSS.

Пример:

.container {
  display: flex;
}

Если старые браузеры требуют префиксов, Autoprefixer автоматически добавит:

.container {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}

Настройка PostCSS

module.exports = {
  plugins: [
    require('autoprefixer')
  ]
};

Autoprefixer автоматически читает Browserslist.


Влияние на размер bundle

Чем больше старых браузеров поддерживается, тем:

  • больше транспиляции;
  • больше полифилов;
  • больше итоговый bundle;
  • ниже производительность.

Пример различий сборки

Современные браузеры

Исходный код:

const getName = user => user?.name ?? 'Unknown';

После сборки может остаться почти без изменений.


Поддержка старых браузеров

Код преобразуется в:

var getName = function(user) {
  return user && user.name != null
    ? user.name
    : 'Unknown';
};

Размер кода увеличивается.


Влияние на tree shaking

Современные браузеры поддерживают ES Modules.

Если Browserslist допускает только современные платформы, Webpack может эффективнее использовать:

  • tree shaking;
  • module concatenation;
  • dead code elimination.

Поддержка ES Modules

Современная конфигурация:

supports es6-module

Позволяет:

  • отказаться от legacy-кода;
  • уменьшить размер bundle;
  • ускорить загрузку.

Legacy и modern bundles

Крупные приложения иногда создают две версии:

Modern bundle

Для современных браузеров:

supports es6-module

Legacy bundle

Для старых браузеров:

> 0.5%
not dead

Такой подход:

  • уменьшает размер современных сборок;
  • сохраняет совместимость;
  • ускоряет загрузку.

Использование с Babel Loader

Пример Webpack-конфигурации:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  }
};

Babel автоматически использует Browserslist.


Явное указание targets

Вместо Browserslist можно использовать:

presets: [
  [
    '@babel/preset-env',
    {
      targets: {
        chrome: '90'
      }
    }
  ]
]

Однако это создаёт дублирование конфигурации.

Browserslist предпочтительнее, поскольку используется всей экосистемой.


Опасность слишком широкой поддержки

Конфигурация:

> 0.1%

Может включать:

  • очень старые Android Browser;
  • старые Samsung Internet;
  • устаревшие мобильные браузеры.

Последствия:

  • огромный bundle;
  • медленная сборка;
  • большое количество полифилов;
  • ухудшение производительности.

Типичная современная конфигурация

Для большинства production-проектов:

> 0.5%
last 2 versions
not dead
not IE 11

Конфигурация для корпоративных систем

Если требуется поддержка старых браузеров:

> 0.2%
not dead
IE 11

В этом случае необходимо учитывать:

  • значительное увеличение bundle;
  • ограничения синтаксиса;
  • необходимость большого количества полифилов.

Browserslist и Node.js

Browserslist поддерживает не только браузеры.

Пример:

node 20

или:

maintained node versions

Это особенно полезно для:

  • SSR;
  • backend-сборок;
  • библиотек;
  • CLI-инструментов.

Проверка покрытия браузеров

Команда:

npx browserslist --coverage

Показывает процент пользователей, охваченных конфигурацией.

Пример:

These browsers account for 92.4% of all users globally

Региональные настройки

Можно учитывать региональную статистику.

Пример:

> 1% in US

или:

> 1% in KZ

Это важно для локальных проектов.


Исключение конкретных браузеров

not op_mini all

или:

not samsung 4

Browserslist и производительность сборки

Чем меньше транспиляции требуется:

  • тем быстрее Babel;
  • тем меньше работа minimizer-плагинов;
  • тем быстрее tree shaking;
  • тем меньше итоговый bundle.

Поэтому поддержка устаревших браузеров напрямую влияет на скорость CI/CD.


Browserslist в монорепозиториях

В монорепозиториях часто используется:

  • общий .browserslistrc;
  • отдельные настройки для packages;
  • разделение browser/server targets.

Частые ошибки

Отсутствие Browserslist

В этом случае инструменты используют значения по умолчанию.

Это может привести к неожиданной транспиляции.


Слишком старая база caniuse-lite

Появляется предупреждение:

Browserslist: caniuse-lite is outdated

Требуется обновление базы.


Конфликт targets и Browserslist

Если одновременно используются:

targets

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


Поддержка IE 11 без полифилов

Даже после транспиляции могут отсутствовать:

  • Promise
  • Map
  • Set
  • Array.from

Нужны полифилы core-js.


Рекомендации для современных проектов

SPA-приложения

> 0.5%
last 2 versions
not dead
not IE 11

Внутренние корпоративные системы

last 1 chrome version

Библиотеки

defaults

или:

maintained node versions

Mobile-first проекты

> 1% in mobile

Команда defaults

Специальный запрос:

defaults

Эквивалентен примерно следующему:

> 0.5%
last 2 versions
Firefox ESR
not dead

Это безопасный базовый вариант для большинства приложений.


Связь Browserslist с Webpack 5

Webpack 5 активно ориентирован на современные браузеры:

  • улучшенная работа с ES Modules;
  • оптимизация tree shaking;
  • поддержка dynamic import;
  • уменьшение legacy-кода.

Правильно настроенный Browserslist позволяет максимально использовать возможности Webpack 5 и одновременно сохранять необходимую совместимость браузеров.