Files
frontend/packages/browserslist-to-targets/index.js

66 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Браузеры, поддерживаемые esbuild/Oxc.
*
* Зачем: browserslist как входной конфиг должен быть приведён к целевому
* формату, который понимает минификатор/трансформер. У esbuild и Oxc
* список целевых браузеров жёстко ограничен и отличается от browserslist.
* Поэтому мы транслируем браузеры из browserslist в короткий esbuild-формат,
* а всё, чего в нём нет — отбрасываем.
*/
const SUPPORTED_TARGETS = new Set(['es', 'chrome', 'edge', 'firefox', 'ios', 'node', 'safari', 'opera', 'ie']);
/**
* Соответствие идентификаторов браузеров browserslist тем, что знает esbuild.
*
* Browserslist различает `ios_saf` (Safari на iOS) и `android` (Chrome на
* Android), тогда как esbuild знает общее `ios` и `chrome`.
*/
const REPLACES = {
ios_saf: 'ios',
android: 'chrome',
};
/**
* Преобразует результат `browserslist()` в массив target-строк для esbuild/Oxc.
*
* Вход — массив записей вида `"chrome 109"`, `"ios_saf 18.5-18.7"`.
* Выход — массив вида `["chrome109", "ios18.5"]`.
*
* Шаги:
* 1. Режем запись на имя и версию.
* 2. Подменяем идентификаторы (`ios_saf → ios`, `android → chrome`).
* 3. Диапазоны версий сводим к нижней границе (`18.5-18.7 → 18.5`).
* 4. Приводим `18.0` к `18` (убираем хвостовой `.0`).
* 5. Отбрасываем версии, не проходящие regex (ломают esbuild), и браузеры,
* которых нет в `SUPPORTED_TARGETS` (`and_chr`, `kaios`, `samsung` и т.д.).
* 6. Для каждого браузера оставляем самую старую версию — esbuild применяет
* трансформации, покрывающие самую консервативную цель.
* 7. Собираем целевые строки без пробела: `chrome109`.
*
* @param {string[]} browsers - массив строк браузеров от `browserslist()`.
* @returns {string[]} массив target-строк совместимый с esbuild/Oxc.
*/
export const browserslistToTargets = (browsers) => {
const result = new Map();
for (const browser of browsers) {
// Шаг 1: ['chrome', '109'].
let [name, version] = browser.split(' ');
// Шаг 2: подмена идентификаторов.
name = REPLACES[name] ?? name;
// Шаг 3: диапазон → нижняя граница.
version = version.includes('-') ? version.slice(0, version.indexOf('-')) : version;
// Шаг 4: `18.0` → `18`, но `18.5` не должно трогаться.
version = version.endsWith('.0') ? version.slice(0, -2) : version;
// Шаг 5: валидная версия + поддерживаемый браузер.
if (/^\d+(\.\d+)*$/.test(version) && SUPPORTED_TARGETS.has(name)) {
// Шаг 6: самая старая версия (последняя в списке) перезатирает предыдущую.
result.set(name, version);
}
}
// Шаг 7: собираем без пробела.
return [...result].map(([name, version]) => `${name}${version}`);
};