Режим наблюдения (watch) в esbuild предназначен для автоматического повторного выполнения сборки при изменении входных файлов. В отличие от классических сборщиков, которые пересобирают проект полностью при каждом изменении, esbuild опирается на инкрементальную модель, что позволяет существенно снижать задержки между изменением кода и обновлением результата.
В основе watch-режима лежит постоянное отслеживание графа зависимостей проекта. При первой сборке esbuild:
При изменении любого файла из графа запускается повторная сборка, но не с нуля — используется ранее построенный кэш и пересчитываются только затронутые части графа.
Ключевая характеристика:
watch ≠ полная пересборка, watch = инкрементальный пересчёт графа зависимостей
В CLI-режиме watch активируется флагом --watch:
esbuild src/index.js --bundle --outfile=dist/bundle.js --watch
После запуска процесс не завершается. Вместо этого esbuild:
Типичное поведение при изменении файла:
[watch] build started
[watch] build finished in 42ms
В API esbuild watch включается через параметр watch в
build:
import esbuild fr om "esbuild";
esbuild.build({
entryPoints: ["src/index.js"],
bundle: true,
outfile: "dist/bundle.js",
watch: {
onRebuild(error, result) {
if (error) {
console.error("Ошибка пересборки:", error);
} else {
console.log("Пересборка завершена");
}
}
}
});
onRebuild вызывается после каждого изменения файлов.
Сигнатура:
error — ошибка компиляции (если есть);result — результат сборки при успешной пересборке.Использование:
Современный подход esbuild основан на context, который
заменяет классический build для долгоживущих процессов.
import * as esbuild from "esbuild";
const ctx = await esbuild.context({
entryPoints: ["src/index.js"],
bundle: true,
outfile: "dist/bundle.js"
});
await ctx.watch();
await ctx.dispose();
Это корректно освобождает файловые наблюдатели и память.
Главная особенность watch в esbuild — агрессивное использование инкрементальности.
При первом запуске:
При изменении файла:
Это даёт:
esbuild использует системные механизмы наблюдения файлов:
На Linux возможны ошибки вида:
ENOSPC: System lim it for number of file watchers reached
Решение — увеличение лимита inotify:
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Watch может работать нестабильно:
esbuild автоматически исключает:
Но дополнительно можно уменьшать нагрузку через плагины:
plugins: [{
name: "ignore-large",
setup(build) {
build.onResolve({ filter: /large-lib/ }, () => {
return { path: "empty-module.js" };
});
}
}]
Watch в таком случае не будет отслеживать реальные изменения внутри исключённого модуля.
При ошибке:
Важно:
Типичный сценарий — связка с HTTP сервером:
import esbuild from "esbuild";
import http from "http";
const ctx = await esbuild.context({
entryPoints: ["src/index.js"],
bundle: true,
outfile: "dist/bundle.js"
});
await ctx.watch();
http.createServer((req, res) => {
res.end("dev server running");
}).listen(3000);
В более сложных конфигурациях:
Плагины esbuild могут влиять на watch-поведение.
Если плагин:
то необходимо корректно объявлять зависимости:
build.onLoad({ filter: /\.txt$/ }, async (args) => {
const contents = await fs.promises.readFile(args.path, "utf8");
return {
contents,
loader: "text"
};
});
Если файл читается, но не зарегистрирован как зависимость, watch может не отследить изменения.
Если модуль не импортируется напрямую или косвенно, изменения игнорируются.
Разные пути могут восприниматься как разные модули:
./utils.js../utils.jsПри использовании onResolve и onLoad
необходимо вручную обеспечивать триггер обновления.
В крупных кодовых базах watch сохраняет стабильность благодаря:
Однако возможны узкие места:
onLoad могут замедлять
rebuild.esbuild корректно обрабатывает несколько точек входа:
entryPoints: ["src/a.js", "src/b.js"]
Поведение:
В монорепозиториях важно учитывать:
Оптимизация:
absWorkingDir;