Опция onRequest используется в механизме разработки и локального сервера Esbuild для перехвата и обработки информации о входящих HTTP-запросах. Она позволяет получать сведения о каждом запросе, поступающем на встроенный сервер, выполнять логирование, собирать статистику, отслеживать ошибки и анализировать поведение клиентских приложений во время разработки.
Наиболее часто данная возможность применяется совместно с методом
serve(), когда Esbuild выступает в роли локального
веб-сервера.
Логирование запросов помогает решать несколько задач:
При поступлении запроса Esbuild формирует объект с информацией о
событии и передаёт его в обработчик onRequest.
Упрощённая схема выглядит следующим образом:
onRequest.Таким образом появляется возможность наблюдать все обращения к серверу в реальном времени.
import * as esbuild from 'esbuild';
await esbuild.serve(
{
servedir: 'public',
onRequest(args) {
console.log(args);
}
},
{}
);
При каждом запросе в консоль будет выводиться объект с информацией о запросе.
Пример результата:
{
method: 'GET',
path: '/app.js',
status: 200,
remoteAddress: '127.0.0.1',
timeInMS: 3
}
В обработчик передаётся объект с набором полезных свойств.
HTTP-метод запроса.
onRequest(args) {
console.log(args.method);
}
Возможные значения:
GET
POST
PUT
DELETE
PATCH
OPTIONS
HEAD
Пример вывода:
GET
Путь к запрашиваемому ресурсу.
onRequest(args) {
console.log(args.path);
}
Результат:
/index.html
или
/assets/main.js
Это позволяет определить, какие файлы наиболее активно используются приложением.
HTTP-статус ответа.
onRequest(args) {
console.log(args.status);
}
Возможные значения:
200
301
302
404
500
Пример:
404
Логирование кодов ответа является одним из наиболее полезных
сценариев применения onRequest.
IP-адрес клиента, отправившего запрос.
onRequest(args) {
console.log(args.remoteAddress);
}
Пример:
127.0.0.1
или
::1
При локальной разработке обычно отображается адрес текущей машины.
Время обработки запроса в миллисекундах.
onRequest(args) {
console.log(args.timeInMS);
}
Пример:
4
Это значение позволяет оценивать скорость отдачи различных ресурсов.
Наиболее распространённый вариант использования выглядит следующим образом:
await esbuild.serve({
servedir: 'public',
onRequest(args) {
console.log(
`[${args.method}] ${args.path} ${args.status}`
);
}
});
Вывод:
[GET] /index.html 200
[GET] /app.js 200
[GET] /logo.svg 200
Такой формат значительно удобнее стандартного вывода объекта целиком.
Часто требуется фиксировать время выполнения запроса.
await esbuild.serve({
servedir: 'public',
onRequest(args) {
const timestamp = new Date().toISOString();
console.log(
`${timestamp} ${args.method} ${args.path}`
);
}
});
Результат:
2025-01-10T14:22:03.123Z GET /app.js
2025-01-10T14:22:03.126Z GET /style.css
Подобный формат используется во многих системах журналирования.
Для улучшения читаемости можно выделять разные типы запросов цветом.
await esbuild.serve({
servedir: 'public',
onRequest(args) {
const color =
args.status >= 400
? '\x1b[31m'
: '\x1b[32m';
console.log(
`${color}${args.method} ${args.path} ${args.status}\x1b[0m`
);
}
});
Зелёным цветом отображаются успешные ответы, красным — ошибки.
При большом количестве запросов полезно выводить только проблемные обращения.
await esbuild.serve({
servedir: 'public',
onRequest(args) {
if (args.status >= 400) {
console.error(
`${args.status}: ${args.path}`
);
}
}
});
Пример:
404: /missing.js
404: /favicon.ico
Это позволяет быстро находить отсутствующие файлы.
Иногда необходимо обнаружить ресурсы, которые загружаются слишком долго.
await esbuild.serve({
servedir: 'public',
onRequest(args) {
if (args.timeInMS > 100) {
console.warn(
`Slow request: ${args.path} (${args.timeInMS} ms)`
);
}
}
});
Пример:
Slow request: /large-image.png (156 ms)
Подобная техника помогает выявлять проблемы производительности.
Обработчик может использоваться для накопления статистики.
const stats = {
requests: 0
};
await esbuild.serve({
servedir: 'public',
onRequest(args) {
stats.requests++;
console.log(
`Total requests: ${stats.requests}`
);
}
});
Вывод:
Total requests: 1
Total requests: 2
Total requests: 3
Часто требуется определить, какие ресурсы используются чаще всего.
const counters = {
js: 0,
css: 0,
html: 0
};
await esbuild.serve({
servedir: 'public',
onRequest(args) {
if (args.path.endsWith('.js')) {
counters.js++;
}
if (args.path.endsWith('.css')) {
counters.css++;
}
if (args.path.endsWith('.html')) {
counters.html++;
}
console.log(counters);
}
});
Возможный результат:
{
js: 12,
css: 4,
html: 1
}
Во многих проектах используются единообразные журналы событий.
Пример создания структурированного сообщения:
await esbuild.serve({
servedir: 'public',
onRequest(args) {
const log = {
method: args.method,
path: args.path,
status: args.status,
duration: args.timeInMS
};
console.log(JSON.stringify(log));
}
});
Вывод:
{
"method":"GET",
"path":"/app.js",
"status":200,
"duration":2
}
Такой формат удобно передавать в системы мониторинга и анализа логов.
Вместо консоли информация может записываться в журнал.
import fs from 'fs';
await esbuild.serve({
servedir: 'public',
onRequest(args) {
const line =
`${args.method} ${args.path} ${args.status}\n`;
fs.appendFileSync('server.log', line);
}
});
Содержимое файла:
GET /index.html 200
GET /app.js 200
GET /image.png 200
Подобный подход полезен при длительном тестировании приложения.
Одной из самых частых задач является отслеживание отсутствующих файлов.
await esbuild.serve({
servedir: 'public',
onRequest(args) {
if (args.status === 404) {
console.error(
`Missing file: ${args.path}`
);
}
}
});
Вывод:
Missing file: /old-script.js
Missing file: /assets/logo-old.svg
Это помогает поддерживать актуальность ссылок и импортов.
С помощью onRequest можно увидеть полный набор ресурсов,
запрашиваемых браузером.
await esbuild.serve({
servedir: 'public',
onRequest(args) {
console.log(args.path);
}
});
Например:
/
/index.css
/app.js
/fonts/main.woff2
/logo.svg
По журналу легко определить порядок загрузки файлов приложения.
Обработчик способен отправлять данные во внешние сервисы.
await esbuild.serve({
servedir: 'public',
onRequest(args) {
sendMetric({
path: args.path,
status: args.status,
duration: args.timeInMS
});
}
});
Подобная интеграция позволяет строить графики:
Несмотря на полезность механизма, необходимо учитывать несколько особенностей.
onRequest ориентирован на наблюдение и логирование.
Он не используется для:
Для подобных задач обычно применяются полноценные HTTP-серверы, например Node.js с Express, Fastify или Koa.
Встроенный сервер Esbuild создавался прежде всего для локальной разработки и тестирования.
Поэтому onRequest чаще всего применяется для:
При большом количестве ресурсов обработчик может вызываться сотни раз за короткий промежуток времени.
Например:
GET /index.html
GET /app.js
GET /runtime.js
GET /vendor.js
GET /logo.svg
GET /fonts/main.woff2
GET /styles.css
Избыточное логирование способно замедлять работу приложения, поэтому в крупных проектах обычно применяют фильтрацию событий.
await esbuild.serve({
servedir: 'public',
onRequest(args) {
const date = new Date().toISOString();
const message =
`[${date}] ` +
`${args.remoteAddress} ` +
`${args.method} ` +
`${args.path} ` +
`${args.status} ` +
`${args.timeInMS}ms`;
console.log(message);
if (args.status >= 400) {
console.error(
`Request failed: ${args.path}`
);
}
if (args.timeInMS > 100) {
console.warn(
`Slow request detected: ${args.path}`
);
}
}
});
Пример результата:
[2025-01-10T14:40:02.222Z] 127.0.0.1 GET /index.html 200 2ms
[2025-01-10T14:40:02.225Z] 127.0.0.1 GET /app.js 200 4ms
[2025-01-10T14:40:02.228Z] 127.0.0.1 GET /missing.js 404 1ms
Request failed: /missing.js
Такой подход обеспечивает полноценное журналирование, позволяет
контролировать ошибки, анализировать производительность и получать
подробную информацию о работе локального сервера Esbuild через единую
точку наблюдения — обработчик onRequest.