Вендорные префиксы: что делает и чего не делает esbuild

Вендорные префиксы в CSS — это механизм, который исторически использовался браузерами для внедрения экспериментальных или нестандартизированных возможностей. Такие свойства имели префиксы вида -webkit-, -moz-, -ms-, -o-, например:

.box {
  -webkit-transform: translateX(10px);
  -moz-transform: translateX(10px);
  transform: translateX(10px);
}

Со временем большая часть этих префиксов утратила необходимость, поскольку спецификации стабилизировались, а браузеры унифицировали реализацию стандартных свойств. Однако вопрос автоматической расстановки префиксов остался важной частью фронтенд-сборки.

Современные инструменты сборки по-разному решают эту задачу, и esbuild занимает в этом процессе строго ограниченную позицию: он сознательно не является системой постобработки CSS уровня Autoprefixer и не пытается угадывать совместимость браузеров.


Что esbuild делает с CSS и почему это важно

Основная цель esbuild — скорость и минимализм архитектуры. Поэтому работа с CSS реализована как базовый слой обработки, без расширенной семантической трансформации.

При обработке CSS esbuild:

  • объединяет CSS-файлы в бандл;
  • минимизирует код (удаляет пробелы, комментарии, лишние символы);
  • поддерживает импорт CSS из JavaScript/TypeScript;
  • может встраивать CSS в JS-бандл или выносить в отдельный файл;
  • обрабатывает URL-ресурсы (например, url() в стилях).

Но принципиально важно: esbuild не модифицирует CSS на уровне совместимости браузеров.


Что esbuild не делает: отсутствие автоматических вендорных префиксов

Одно из ключевых ограничений заключается в том, что esbuild не добавляет вендорные префиксы автоматически.

Это означает:

  • не происходит генерации -webkit-, -moz- и других префиксов;
  • не анализируется поддержка CSS-свойств в разных браузерах;
  • не применяется логика вроде Can I Use-совместимости;
  • отсутствует встроенный аналог Autoprefixer.

Например, следующий CSS:

.button {
  user-select: none;
}

после обработки esbuild останется без изменений (кроме минификации), а не превратится в:

.button {
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

Причина отсутствия автопрефиксации в архитектуре esbuild

Решение не включать автопрефиксацию связано с несколькими принципами проектирования:

1. Минимизация зоны ответственности

esbuild концентрируется на:

  • трансляции JavaScript/TypeScript;
  • объединении модулей;
  • минимизации кода;
  • ускорении сборки.

CSS-постобработка уровня совместимости считается отдельной задачей, выходящей за рамки бандлера.


2. Избежание дублирования экосистемных решений

В экосистеме уже существует специализированный инструмент:

  • PostCSS + Autoprefixer

Он решает задачу на уровне AST CSS и поддерживает:

  • гибкую конфигурацию;
  • поддержку Browserslist;
  • плагинную архитектуру.

Добавление аналогичной логики в esbuild привело бы к дублированию функциональности и усложнению ядра.


3. Приоритет скорости

esbuild проектировался как один из самых быстрых сборщиков. Любая глубокая CSS-обработка:

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

Отказ от этого слоя позволяет сохранять предсказуемую производительность.


Как на самом деле решается задача вендорных префиксов

В современных сборках роль esbuild обычно ограничена «транспортировкой» CSS, а не его семантической модификацией.

Типичная архитектура выглядит так:

CSS/SCSS → PostCSS (Autoprefixer) → esbuild → финальный бандл

или:

SCSS → PostCSS → CSS → esbuild (bundle/minify)

Интеграция Autoprefixer через плагины

Хотя esbuild не поддерживает автопрефиксацию нативно, он предоставляет плагинную систему, через которую можно подключить PostCSS.

Пример типичной конфигурации:

import esbuild from "esbuild";
import postcss from "postcss";
import autoprefixer from "autoprefixer";
import fs from "fs";

const postcssPlugin = {
  name: "postcss",
  setup(build) {
    build.onLoad({ filter: /\.css$/ }, async (args) => {
      const css = await fs.promises.readFile(args.path, "utf8");

      const result = await postcss([autoprefixer]).process(css, {
        from: args.path
      });

      return {
        contents: result.css,
        loader: "css"
      };
    });
  }
};

esbuild.build({
  entryPoints: ["src/index.js"],
  bundle: true,
  outdir: "dist",
  plugins: [postcssPlugin]
});

Здесь видно, что esbuild выступает как оркестратор, а не как CSS-движок.


Важное различие: трансформация vs постобработка

Поведение можно разделить на два уровня:

Трансформация (то, что делает esbuild)

  • преобразование TypeScript → JavaScript;
  • JSX → JavaScript;
  • ESNext → совместимый JavaScript;
  • объединение модулей.

Постобработка (то, что esbuild не делает)

  • добавление вендорных префиксов;
  • анализ совместимости браузеров;
  • переписывание CSS-правил под старые движки;
  • полифиллинг CSS-свойств.

Практические последствия для проектов

Отсутствие автопрефиксации напрямую влияет на архитектуру проекта:

Необходимо отдельное звено обработки CSS

Проект, использующий только esbuild без PostCSS, получает:

  • более быстрый билд;
  • но потенциально менее совместимый CSS.

Современные браузеры снижают критичность

Во многих проектах необходимость в префиксах уменьшается:

  • flex, grid, transform, transition уже стандартизированы;
  • большинство префиксов устарели;
  • новые свойства быстро получают стабильную поддержку.

Но остаются исключения

Некоторые свойства всё ещё могут требовать префиксов или fallback-логики:

  • user-select;
  • backdrop-filter (в отдельных случаях);
  • старые Android WebKit-браузеры;
  • специфичные enterprise-среды.

Поведение esbuild при минификации CSS

Минификация CSS в esbuild также не затрагивает семантику свойств.

Он:

  • сокращает пробелы;
  • удаляет комментарии;
  • упрощает структуру;
  • может объединять правила при безопасных условиях.

Но он не:

  • добавляет новые свойства;
  • удаляет «неподдерживаемые» свойства;
  • расширяет CSS под разные браузеры.

Ошибочное ожидание «умного CSS»

Распространённое заблуждение заключается в том, что любой современный бандлер должен автоматически:

  • адаптировать CSS под браузеры;
  • вставлять префиксы;
  • исправлять несовместимости.

Однако esbuild придерживается иной философии: он не занимается «пониманием дизайна», он занимается «пересборкой кода».


Роль разработчика в текущей модели

В такой архитектуре ответственность разделяется:

  • esbuild — быстрый сборщик;
  • PostCSS/Autoprefixer — адаптация CSS;
  • браузеры — конечная интерпретация;
  • разработчик — настройка цепочки инструментов.

Это приводит к более модульной системе, где каждый инструмент делает одну вещь, но делает её быстро и предсказуемо.


Итоговое поведение цепочки обработки CSS

Если обобщить поведение esbuild относительно вендорных префиксов:

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

Такое разделение делает систему более предсказуемой и масштабируемой, но требует явной настройки CSS-цепочки в проектах, где важна кроссбраузерная совместимость.