К концу 2010-х годов экосистема JavaScript столкнулась с серьёзной проблемой производительности инструментов сборки. Рост количества модулей, усложнение клиентских приложений и распространение транспиляции через Babel привели к тому, что время сборки крупных проектов начало измеряться десятками секунд и даже минутами.
Наиболее популярными решениями того периода являлись:
Каждый из инструментов обладал собственными преимуществами, однако все они имели общую особенность — сравнительно высокие накладные расходы на обработку большого числа файлов.
На этом фоне появилась идея создания принципиально более быстрого сборщика, ориентированного на максимальную производительность без отказа от современных возможностей JavaScript.
Esbuild был создан разработчиком Evan Wallace.
До появления Esbuild он был известен благодаря работе над графическими технологиями, инструментами разработки и высокопроизводительными проектами, связанными с WebGL и компиляторами.
Основной целью разработки Esbuild стало решение нескольких задач одновременно:
Одним из наиболее важных архитектурных решений стал выбор языка Go вместо JavaScript или TypeScript.
Большинство популярных сборщиков работают внутри среды Node.js и наследуют её ограничения:
Esbuild был написан на Go, что обеспечило несколько преимуществ:
После сборки Esbuild представляет собой самостоятельный исполняемый бинарный файл.
Это позволяет:
Go предоставляет производительные механизмы управления памятью и конкурентного выполнения задач.
В результате Esbuild способен обрабатывать тысячи файлов значительно быстрее многих конкурентов.
Многие этапы сборки выполняются одновременно:
На многоядерных процессорах это обеспечивает серьёзный прирост скорости.
Первые публичные версии Esbuild появились в 2020 году.
Уже на ранних этапах развития проект привлёк внимание сообщества благодаря впечатляющим результатам тестирования.
Во многих бенчмарках наблюдалось ускорение:
Именно скорость стала главным фактором популярности нового инструмента.
Несмотря на молодой возраст проекта, первые версии уже содержали значительный набор функций.
Поддерживалась сборка множества модулей в единый пакет.
Пример:
import { sum } from './math.js';
console.log(sum(10, 20));
После обработки Esbuild формировал итоговый бандл, пригодный для запуска в браузере или Node.js.
С самого начала была реализована встроенная минификация:
esbuild app.js --minify
Удалялись:
Esbuild умел устранять неиспользуемый код.
Исходный модуль:
export function used() {}
export function unused() {}
Использование:
import { used } from './utils.js';
used();
В итоговой сборке функция unused удалялась.
Инструмент поддерживал преобразование современного синтаксиса JavaScript в более старые версии ECMAScript.
Пример:
const user = data?.profile?.name;
Мог быть преобразован в код, совместимый со старыми браузерами.
Одним из ключевых этапов эволюции стала интеграция TypeScript.
Esbuild получил возможность напрямую обрабатывать файлы:
.ts
.tsx
Пример:
interface User {
name: string;
}
const user: User = {
name: 'Alex'
};
Во время сборки типы удаляются, а на выходе получается обычный JavaScript.
Особенность реализации заключается в том, что Esbuild не выполняет полноценную проверку типов.
Он занимается исключительно трансформацией кода.
Поэтому в крупных проектах обычно используется связка:
TypeScript Compiler (tsc)
+
Esbuild
где:
tsc отвечает за проверку типов;Практически сразу после появления Esbuild получил поддержку JSX.
Пример:
function App() {
return <h1>Hello</h1>;
}
Во время компиляции JSX преобразуется в стандартные вызовы JavaScript.
Позднее были добавлены:
Это позволило использовать Esbuild в качестве полноценного инструмента сборки React-проектов.
Первые версии проекта концентрировались преимущественно на JavaScript.
Однако впоследствии функциональность CSS значительно расширилась.
Появилась поддержка:
url();Пример:
@import './theme.css';
.button {
color: red;
}
Esbuild автоматически объединяет зависимости и формирует итоговый набор стилей.
Одной из важных задач стало обеспечение совместимости с разными системами модулей.
Поддерживаются:
Современный стандарт ECMAScript Modules:
import { helper } from './helper.js';
Традиционный формат Node.js:
const helper = require('./helper');
Формат для прямого подключения в браузере:
<script src="bundle.js"></script>
Используются для обеспечения совместимости со старыми окружениями.
По мере роста популярности возникла необходимость расширяемости.
Для решения этой задачи была реализована 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.
Изначально Esbuild часто использовался через командную строку.
Позднее всё большее значение начал приобретать программный API.
Пример:
import * as esbuild from 'esbuild';
await esbuild.build({
entryPoints: ['src/index.js'],
outfile: 'dist/app.js',
bundle: true
});
Это позволило интегрировать инструмент:
Следующим важным этапом развития стала поддержка повторных сборок.
При изменении файлов не требуется заново анализировать весь проект.
Используется информация, сохранённая после предыдущего запуска.
Преимущества:
Для больших приложений выигрыш может составлять секунды на каждом изменении.
Для разработки был реализован режим отслеживания изменений.
Пример:
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 для:
Благодаря этому достигается практически мгновенный старт сервера разработки.
Также Esbuild используется в:
На протяжении развития проекта производительность оставалась главным приоритетом.
Оптимизации регулярно затрагивали:
В отличие от многих инструментов, где новые функции часто приводят к замедлению работы, развитие Esbuild сопровождалось постоянным сохранением высокой скорости.
С каждой новой версией расширялась поддержка современных возможностей языка.
Добавлялась обработка:
Пример:
const result = config ?? defaultConfig;
Esbuild способен либо сохранить конструкцию в исходном виде, либо преобразовать её для старых платформ.
Со временем появилась гибкая настройка целевых окружений.
Пример:
esbuild app.js \
--target=es2020
или
esbuild app.js \
--target=chrome110
Это позволяет управлять:
На текущем этапе Esbuild представляет собой зрелую систему сборки, сочетающую:
История развития Esbuild демонстрирует редкий для инструментов фронтенд-разработки путь: от экспериментального проекта, ориентированного исключительно на скорость, до одного из ключевых компонентов современной экосистемы JavaScript, оказывающего влияние на архитектуру множества популярных инструментов и процессов сборки.