Версии и история развития

К концу 2010-х годов экосистема JavaScript столкнулась с серьёзной проблемой производительности инструментов сборки. Рост количества модулей, усложнение клиентских приложений и распространение транспиляции через Babel привели к тому, что время сборки крупных проектов начало измеряться десятками секунд и даже минутами.

Наиболее популярными решениями того периода являлись:

  • Webpack;
  • Rollup;
  • Parcel;
  • Browserify.

Каждый из инструментов обладал собственными преимуществами, однако все они имели общую особенность — сравнительно высокие накладные расходы на обработку большого числа файлов.

На этом фоне появилась идея создания принципиально более быстрого сборщика, ориентированного на максимальную производительность без отказа от современных возможностей JavaScript.


Автор проекта

Esbuild был создан разработчиком Evan Wallace.

До появления Esbuild он был известен благодаря работе над графическими технологиями, инструментами разработки и высокопроизводительными проектами, связанными с WebGL и компиляторами.

Основной целью разработки Esbuild стало решение нескольких задач одновременно:

  • радикальное ускорение сборки;
  • уменьшение потребления памяти;
  • упрощение конфигурации;
  • поддержка современных стандартов ECMAScript;
  • интеграция с существующей экосистемой JavaScript.

Выбор языка Go

Одним из наиболее важных архитектурных решений стал выбор языка Go вместо JavaScript или TypeScript.

Большинство популярных сборщиков работают внутри среды Node.js и наследуют её ограничения:

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

Esbuild был написан на Go, что обеспечило несколько преимуществ:

Компиляция в нативный код

После сборки Esbuild представляет собой самостоятельный исполняемый бинарный файл.

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

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

Эффективная работа с памятью

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

В результате Esbuild способен обрабатывать тысячи файлов значительно быстрее многих конкурентов.

Параллелизм

Многие этапы сборки выполняются одновременно:

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

На многоядерных процессорах это обеспечивает серьёзный прирост скорости.


Первый публичный релиз

Первые публичные версии Esbuild появились в 2020 году.

Уже на ранних этапах развития проект привлёк внимание сообщества благодаря впечатляющим результатам тестирования.

Во многих бенчмарках наблюдалось ускорение:

  • в десятки раз по сравнению с Webpack;
  • в несколько раз по сравнению с Rollup;
  • существенное сокращение времени горячей пересборки.

Именно скорость стала главным фактором популярности нового инструмента.


Ранние возможности

Несмотря на молодой возраст проекта, первые версии уже содержали значительный набор функций.

Bundling

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

Пример:

import { sum } from './math.js';

console.log(sum(10, 20));

После обработки Esbuild формировал итоговый бандл, пригодный для запуска в браузере или Node.js.

Минификация

С самого начала была реализована встроенная минификация:

esbuild app.js --minify

Удалялись:

  • лишние пробелы;
  • комментарии;
  • неиспользуемые конструкции.

Tree Shaking

Esbuild умел устранять неиспользуемый код.

Исходный модуль:

export function used() {}
export function unused() {}

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

import { used } from './utils.js';

used();

В итоговой сборке функция unused удалялась.

Транспиляция

Инструмент поддерживал преобразование современного синтаксиса JavaScript в более старые версии ECMAScript.

Пример:

const user = data?.profile?.name;

Мог быть преобразован в код, совместимый со старыми браузерами.


Развитие поддержки TypeScript

Одним из ключевых этапов эволюции стала интеграция TypeScript.

Esbuild получил возможность напрямую обрабатывать файлы:

.ts
.tsx

Пример:

interface User {
    name: string;
}

const user: User = {
    name: 'Alex'
};

Во время сборки типы удаляются, а на выходе получается обычный JavaScript.

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

Он занимается исключительно трансформацией кода.

Поэтому в крупных проектах обычно используется связка:

TypeScript Compiler (tsc)
+
Esbuild

где:

  • tsc отвечает за проверку типов;
  • Esbuild выполняет сборку.

Поддержка JSX и React

Практически сразу после появления Esbuild получил поддержку JSX.

Пример:

function App() {
    return <h1>Hello</h1>;
}

Во время компиляции JSX преобразуется в стандартные вызовы JavaScript.

Позднее были добавлены:

  • React Automatic Runtime;
  • пользовательские JSX-фабрики;
  • поддержка различных библиотек интерфейсов.

Это позволило использовать Esbuild в качестве полноценного инструмента сборки React-проектов.


Развитие возможностей CSS

Первые версии проекта концентрировались преимущественно на JavaScript.

Однако впоследствии функциональность CSS значительно расширилась.

Появилась поддержка:

  • объединения CSS-файлов;
  • минификации стилей;
  • CSS-модулей;
  • загрузки ресурсов через url();
  • обработки импортов.

Пример:

@import './theme.css';

.button {
    color: red;
}

Esbuild автоматически объединяет зависимости и формирует итоговый набор стилей.


Поддержка различных форматов модулей

Одной из важных задач стало обеспечение совместимости с разными системами модулей.

Поддерживаются:

ESM

Современный стандарт ECMAScript Modules:

import { helper } from './helper.js';

CommonJS

Традиционный формат Node.js:

const helper = require('./helper');

IIFE

Формат для прямого подключения в браузере:

<script src="bundle.js"></script>

UMD-подобные сценарии

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


Появление системы плагинов

По мере роста популярности возникла необходимость расширяемости.

Для решения этой задачи была реализована Plugin API.

Архитектура плагинов позволяет вмешиваться в процесс сборки на разных этапах.

Пример регистрации плагина:

import * as esbuild from 'esbuild';

const plugin = {
    name: 'demo',
    setup(build) {
        build.onResolve({ filter: /.*/ }, args => {
            return {
                path: args.path
            };
        });
    }
};

await esbuild.build({
    entryPoints: ['app.js'],
    bundle: true,
    plugins: [plugin]
});

Появление плагинов существенно расширило сферу применения Esbuild.


Поддержка API для JavaScript

Изначально Esbuild часто использовался через командную строку.

Позднее всё большее значение начал приобретать программный API.

Пример:

import * as esbuild from 'esbuild';

await esbuild.build({
    entryPoints: ['src/index.js'],
    outfile: 'dist/app.js',
    bundle: true
});

Это позволило интегрировать инструмент:

  • в собственные сборочные процессы;
  • в CLI-приложения;
  • в серверные платформы;
  • в DevOps-сценарии.

Инкрементальная сборка

Следующим важным этапом развития стала поддержка повторных сборок.

При изменении файлов не требуется заново анализировать весь проект.

Используется информация, сохранённая после предыдущего запуска.

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

  • быстрые пересборки;
  • улучшенный опыт разработки;
  • снижение нагрузки на систему.

Для больших приложений выигрыш может составлять секунды на каждом изменении.


Режим наблюдения за файлами

Для разработки был реализован режим отслеживания изменений.

Пример:

esbuild src/index.js \
  --bundle \
  --watch

После сохранения файла выполняется автоматическая пересборка.

Функциональность особенно востребована при разработке интерфейсов и одностраничных приложений.


Появление встроенного сервера разработки

Поздние версии получили встроенный HTTP-сервер.

Пример:

const ctx = await esbuild.context({
    entryPoints: ['src/index.js'],
    bundle: true
});

await ctx.serve({
    servedir: 'public'
});

Это позволило запускать проекты без подключения сторонних решений.


Интеграция с современными инструментами

С ростом популярности Esbuild стал основой или важной частью множества проектов.

Наиболее известным примером является Vite.

На ранних этапах запуска Vite использует Esbuild для:

  • быстрого преобразования зависимостей;
  • обработки TypeScript;
  • трансформации JSX.

Благодаря этому достигается практически мгновенный старт сервера разработки.

Также Esbuild используется в:

  • генераторах статических сайтов;
  • серверных фреймворках;
  • инструментах тестирования;
  • облачных платформах;
  • системах CI/CD.

Эволюция производительности

На протяжении развития проекта производительность оставалась главным приоритетом.

Оптимизации регулярно затрагивали:

  • парсер JavaScript;
  • генератор кода;
  • алгоритмы минификации;
  • обработку графа зависимостей;
  • кэширование;
  • работу с файловой системой.

В отличие от многих инструментов, где новые функции часто приводят к замедлению работы, развитие Esbuild сопровождалось постоянным сохранением высокой скорости.


Поддержка новых стандартов JavaScript

С каждой новой версией расширялась поддержка современных возможностей языка.

Добавлялась обработка:

  • optional chaining;
  • nullish coalescing;
  • top-level await;
  • динамических импортов;
  • новых синтаксических конструкций ECMAScript.

Пример:

const result = config ?? defaultConfig;

Esbuild способен либо сохранить конструкцию в исходном виде, либо преобразовать её для старых платформ.


Развитие системы целевых платформ

Со временем появилась гибкая настройка целевых окружений.

Пример:

esbuild app.js \
  --target=es2020

или

esbuild app.js \
  --target=chrome110

Это позволяет управлять:

  • совместимостью;
  • размером итогового кода;
  • степенью транспиляции.

Современное состояние проекта

На текущем этапе Esbuild представляет собой зрелую систему сборки, сочетающую:

  • высокую производительность;
  • минималистичный подход к конфигурации;
  • поддержку современных стандартов;
  • развитый API;
  • расширяемость через плагины;
  • интеграцию с TypeScript и React;
  • возможности работы с CSS и статическими ресурсами.

История развития Esbuild демонстрирует редкий для инструментов фронтенд-разработки путь: от экспериментального проекта, ориентированного исключительно на скорость, до одного из ключевых компонентов современной экосистемы JavaScript, оказывающего влияние на архитектуру множества популярных инструментов и процессов сборки.