Система плагинов Parcel состоит из нескольких специализированных типов расширений: Transformer, Resolver, Bundler, Optimizer, Packager, Compressor, Runtime и Reporter. Каждый из них отвечает за определённый этап сборочного процесса. Reporter занимает особое место, поскольку не изменяет исходный код, не участвует в упаковке модулей и не влияет на итоговые артефакты напрямую. Его задача заключается в получении информации о ходе сборки и последующем выполнении произвольных действий на основе этих данных.
Reporter-плагин работает как наблюдатель за жизненным циклом Parcel. Он получает поток событий и может:
Фактически Reporter представляет собой механизм подписки на события сборочного процесса.
Reporter реализуется через пакет @parcel/plugin.
Базовая структура выглядит следующим образом:
const {Reporter} = require('@parcel/plugin');
module.exports = new Reporter({
report({event, options, logger}) {
// обработка событий
}
});
Parcel создаёт экземпляр Reporter и вызывает метод
report при возникновении различных событий внутри
сборщика.
Параметры метода:
| Параметр | Назначение |
|---|---|
| event | Информация о текущем событии |
| options | Настройки Parcel |
| logger | Система логирования Parcel |
Главным объектом является именно event, поскольку через
него Reporter получает сведения о происходящем.
Типичная структура проекта Reporter-плагина:
parcel-reporter-example/
├── package.json
├── Reporter.js
└── README.md
Файл package.json:
{
"name": "parcel-reporter-example",
"version": "1.0.0",
"main": "Reporter.js",
"engines": {
"parcel": "^2.0.0"
}
}
Основной файл:
const {Reporter} = require('@parcel/plugin');
module.exports = new Reporter({
report({event}) {
console.log(event.type);
}
});
Такой Reporter будет выводить тип каждого события, происходящего во время работы Parcel.
Parcel использует файл конфигурации .parcelrc.
Пример подключения:
{
"extends": "@parcel/config-default",
"reporters": [
"...",
"./parcel-reporter-example"
]
}
Специальное значение "..." сохраняет стандартные
Reporter-плагины Parcel.
Без него встроенные средства отображения прогресса будут отключены.
Reporter получает объект события следующего вида:
{
type: 'buildStart'
}
Поле type определяет разновидность события.
Основные типы:
buildStart
buildProgress
buildSuccess
buildFailure
log
watchStart
watchEnd
watchProgress
Каждое событие содержит собственный набор данных.
Событие возникает при начале сборки.
Пример:
const {Reporter} = require('@parcel/plugin');
module.exports = new Reporter({
report({event}) {
if (event.type === 'buildStart') {
console.log('Сборка началась');
}
}
});
Практические сценарии:
Например:
let startTime = 0;
module.exports = new Reporter({
report({event}) {
if (event.type === 'buildStart') {
startTime = Date.now();
}
}
});
После успешного завершения сборки Parcel генерирует событие
buildSuccess.
Пример:
module.exports = new Reporter({
report({event}) {
if (event.type === 'buildSuccess') {
console.log('Сборка завершена');
}
}
});
Событие содержит объект сборки:
if (event.type === 'buildSuccess') {
console.log(event.bundleGraph);
}
Через bundleGraph можно получить информацию обо всех
созданных пакетах.
Распространённый сценарий — измерение длительности выполнения.
const {Reporter} = require('@parcel/plugin');
let startTime;
module.exports = new Reporter({
report({event}) {
if (event.type === 'buildStart') {
startTime = Date.now();
}
if (event.type === 'buildSuccess') {
const duration = Date.now() - startTime;
console.log(`Сборка заняла ${duration} мс`);
}
}
});
Подобный Reporter часто используется в крупных проектах для анализа производительности.
При ошибке возникает событие buildFailure.
module.exports = new Reporter({
report({event}) {
if (event.type === 'buildFailure') {
console.error(event.diagnostics);
}
}
});
Свойство diagnostics содержит подробную информацию об
ошибке.
Структура диагностического объекта может включать:
{
message: 'Unexpected token',
origin: 'BabelTransformer',
stack: '...',
codeFrames: [...]
}
Это позволяет создавать собственные системы отображения ошибок.
Reporter может реагировать на ошибки специальным образом.
module.exports = new Reporter({
report({event}) {
if (event.type === 'buildFailure') {
console.log('Сборка завершилась неудачно');
}
}
});
В более сложных случаях можно отправлять уведомления:
const notifier = require('node-notifier');
module.exports = new Reporter({
report({event}) {
if (event.type === 'buildFailure') {
notifier.notify({
title: 'Parcel',
message: 'Обнаружена ошибка сборки'
});
}
}
});
Во время работы Parcel создаёт множество промежуточных событий.
if (event.type === 'buildProgress') {
console.log(event.phase);
}
Поле phase показывает текущий этап обработки.
Например:
resolving
transforming
bundling
packaging
optimizing
Это позволяет реализовать собственный индикатор прогресса.
Простейший пример:
module.exports = new Reporter({
report({event}) {
if (event.type === 'buildProgress') {
process.stdout.write('.');
}
if (event.type === 'buildSuccess') {
console.log('\nГотово');
}
}
});
Более продвинутые реализации используют библиотеки:
const cliProgress = require('cli-progress');
Reporter может обновлять состояние прогресс-бара в зависимости от этапов сборки.
Событие log позволяет получать сообщения
логирования.
module.exports = new Reporter({
report({event}) {
if (event.type === 'log') {
console.log(event.level);
console.log(event.message);
}
}
});
Возможные уровни:
info
verbose
warn
error
progress
success
Это даёт возможность фильтровать сообщения.
Пример Reporter для сохранения логов.
const fs = require('fs');
module.exports = new Reporter({
report({event}) {
if (event.type !== 'log') {
return;
}
fs.appendFileSync(
'parcel.log',
`[${event.level}] ${event.message}\n`
);
}
});
После каждой сборки формируется полный журнал событий.
Parcel предоставляет собственный объект логирования.
module.exports = new Reporter({
report({logger}) {
logger.info({
message: 'Reporter активирован'
});
}
});
Предусмотрены методы:
logger.info(...)
logger.warn(...)
logger.error(...)
logger.verbose(...)
logger.progress(...)
Пример:
logger.warn({
message: 'Обнаружена потенциальная проблема'
});
Сообщение будет корректно обработано встроенной системой вывода Parcel.
Одно из наиболее полезных применений Reporter — создание отчётов.
const fs = require('fs');
module.exports = new Reporter({
report({event}) {
if (event.type !== 'buildSuccess') {
return;
}
const html = `
<html>
<body>
<h1>Сборка завершена</h1>
</body>
</html>
`;
fs.writeFileSync('report.html', html);
}
});
После завершения сборки автоматически создаётся HTML-документ.
После успешной сборки доступен объект графа пакетов.
if (event.type === 'buildSuccess') {
const graph = event.bundleGraph;
}
Через него можно обходить все сформированные bundles.
Пример концептуального обхода:
graph.getBundles().forEach(bundle => {
console.log(bundle.filePath);
});
Полученные данные позволяют:
Reporter может проверять ограничения по размеру.
const fs = require('fs');
module.exports = new Reporter({
report({event}) {
if (event.type !== 'buildSuccess') {
return;
}
for (const bundle of event.bundleGraph.getBundles()) {
const stat = fs.statSync(bundle.filePath);
if (stat.size > 500000) {
console.error(
`${bundle.name} превышает лимит`
);
}
}
}
});
Подобная проверка особенно полезна в CI/CD.
Reporter способен отправлять данные в любые HTTP API.
Пример:
const axios = require('axios');
module.exports = new Reporter({
async report({event}) {
if (event.type === 'buildSuccess') {
await axios.post(
'https://example.com/build',
{
status: 'success',
date: Date.now()
}
);
}
}
});
Возможные направления интеграции:
Практический сценарий автоматизации.
const axios = require('axios');
module.exports = new Reporter({
async report({event}) {
if (event.type === 'buildSuccess') {
await axios.post(
process.env.SLACK_WEBHOOK,
{
text: 'Сборка успешно завершена'
}
);
}
}
});
Аналогичным образом можно подключать:
При использовании parcel watch появляются дополнительные
события.
Например:
if (event.type === 'watchStart') {
console.log('Режим наблюдения активирован');
}
Остановка наблюдения:
if (event.type === 'watchEnd') {
console.log('Наблюдение завершено');
}
Такие события удобны для управления ресурсами и внешними подключениями.
Метод report может быть асинхронным.
module.exports = new Reporter({
async report({event}) {
if (event.type === 'buildSuccess') {
await saveReport();
}
}
});
Это позволяет:
По мере роста функциональности рекомендуется выносить обработчики.
Структура:
src/
├── handlers/
│ ├── buildStart.js
│ ├── buildSuccess.js
│ └── buildFailure.js
├── Reporter.js
└── utils/
Основной файл:
const {Reporter} = require('@parcel/plugin');
const buildStart = require('./handlers/buildStart');
const buildSuccess = require('./handlers/buildSuccess');
module.exports = new Reporter({
async report(context) {
switch (context.event.type) {
case 'buildStart':
return buildStart(context);
case 'buildSuccess':
return buildSuccess(context);
}
}
});
Такой подход упрощает поддержку крупных плагинов.
Минимизировать влияние на скорость сборки.
Reporter выполняется внутри процесса Parcel, поэтому тяжёлые вычисления могут замедлять работу сборщика.
Избегать блокирующих операций.
Предпочтительнее использовать асинхронные версии API:
await fs.promises.writeFile(...);
вместо
fs.writeFileSync(...);
Обрабатывать исключения.
try {
await sendData();
} catch (error) {
console.error(error);
}
Не изменять состояние Parcel напрямую.
Reporter предназначен для наблюдения и анализа, а не для вмешательства в механизм сборки.
Использовать логирование вместо прямого вывода.
logger.info({
message: 'Операция выполнена'
});
Это обеспечивает корректную интеграцию с внутренней системой сообщений Parcel.
const {Reporter} = require('@parcel/plugin');
const fs = require('fs/promises');
let startedAt = 0;
module.exports = new Reporter({
async report({event, logger}) {
switch (event.type) {
case 'buildStart':
startedAt = Date.now();
logger.info({
message: 'Сборка началась'
});
break;
case 'buildSuccess':
const duration =
Date.now() - startedAt;
await fs.writeFile(
'build-report.json',
JSON.stringify({
status: 'success',
duration
}, null, 2)
);
logger.info({
message:
`Сборка завершена за ${duration} мс`
});
break;
case 'buildFailure':
logger.error({
message: 'Ошибка сборки'
});
break;
}
}
});
Такой плагин отслеживает начало и завершение сборки, вычисляет её продолжительность, сохраняет отчёт в JSON-файл и использует встроенную систему логирования Parcel для вывода сообщений.