Reporter
Reporter plugins receive events from Parcel as they happen throughout the build process. For example, reporters may log status information, or statistics about the bundles at the end of a build.
Example
#A Reporter plugin implements a method for each type of event it wants to receive: buildStartbuild_startBuildStartbuildStart, buildSuccessbuild_successBuildSuccessbuildSuccess, buildFailurebuild_failureBuildFailurebuildFailure, and loglogLoglog. At least one of these methods must be implemented, and events without one are skipped. In Go, each method has its own interface, e.g. parcel.BuildSuccessReporter. This example logs the number of bundles and build time when a build is successful.
import { Reporter } from "@parcel/plugin";
export default new Reporter({
buildSuccess({ bundleGraph, buildTime }) {
let bundles = bundleGraph.getBundles();
console.log(`✨ Built ${bundles.length} bundles in ${buildTime}ms!`);
},
});
use parcel_plugin::{BuildSuccess, Diagnostic, Options, Plugin, register_plugin};
struct MyReporter;
impl Plugin for MyReporter {
fn new(_config: &[u8]) -> Result<Self, Diagnostic> {
Ok(MyReporter)
}
fn build_success(&self, event: &BuildSuccess, _options: &Options) -> Result<(), Diagnostic> {
let bundles = event.bundle_graph.bundle_count();
println!("✨ Built {} bundles in {:?}!", bundles, event.build_time);
Ok(())
}
}
register_plugin!(MyReporter);
package main
import (
"fmt"
parcel "github.com/parcel-bundler/parcel/plugin-go/v3"
)
type MyReporter struct{}
func (r *MyReporter) BuildSuccess(event *parcel.BuildSuccess, _ *parcel.Options) error {
bundles := event.BundleGraph.BundleCount()
fmt.Printf("✨ Built %d bundles in %v!\n", bundles, event.BuildTime)
return nil
}
func init() {
parcel.RegisterPlugin(func(config []byte) (any, error) {
return &MyReporter{}, nil
})
}
func main() {}
import ParcelPlugin
struct MyReporter: Reporter {
init(config: NoConfig) {}
func buildSuccess(_ event: BuildSuccess, options: Options) async throws {
let bundles = event.bundleGraph.bundleCount
print("✨ Built \(bundles) bundles in \(event.buildTime)!")
}
}
#parcelPlugin(MyReporter.self)
See Native plugins for how to build native plugins and use them in a project. The rest of the examples on this page omit the setup code, and only show the method for each event.
Each event includes its properties, along with Parcel's options. JavaScript reporters also receive the plugin's config from .parcelrc with each event, and native reporters receive it when they are created. See Configuration for details. Reporters cannot affect the result of a build. If a reporter fails with an error, it is logged, and the build continues.
Note: Messages logged by JavaScript reporters using console methods (or process.stdout/process.stderr) are sent as log events to all reporters, including Parcel's built-in CLI reporter, which prints them. To prevent infinite loops, messages logged while handling a log event may be discarded. Native reporters write to stdout and stderr directly. See Logging for more details.
Build start
#The build start event is emitted when a build is started. In watch mode, it is emitted at the start of each rebuild.
import { Reporter } from "@parcel/plugin";
export default new Reporter({
buildStart() {
console.log("Started build!");
},
});
impl Plugin for MyReporter {
fn build_start(&self, _options: &Options) -> Result<(), Diagnostic> {
println!("Started build!");
Ok(())
}
}
func (r *MyReporter) BuildStart(_ *parcel.Options) error {
fmt.Println("Started build!")
return nil
}
struct MyReporter: Reporter {
func buildStart(options: Options) async throws {
print("Started build!")
}
}
Build success
#The build success event is emitted when a build completes successfully. It includes the full bundle graph that was built, the build time, and a list of the assets that changed. On a full build, the changed assets include every asset, and on rebuilds they include the assets that were transformed again. The build time is a number of milliseconds in JavaScript, and a duration in native plugins. Native plugins receive the changed assets as indices, which can be looked up in the bundle graph.
bundle.filePathbundle.dist_path()bundle.DistPath()bundle.distPath returns the absolute path that each bundle in the bundle graph was written to, or nothing for inline bundles.
import { Reporter } from "@parcel/plugin";
export default new Reporter({
buildSuccess({ changedAssets, buildTime }) {
console.log(`✨ Rebuilt ${changedAssets.length} assets in ${buildTime}ms!`);
},
});
impl Plugin for MyReporter {
fn build_success(&self, event: &BuildSuccess, _options: &Options) -> Result<(), Diagnostic> {
println!("✨ Rebuilt {} assets in {:?}!", event.changed_assets.len(), event.build_time);
Ok(())
}
}
func (r *MyReporter) BuildSuccess(event *parcel.BuildSuccess, _ *parcel.Options) error {
fmt.Printf("✨ Rebuilt %d assets in %v!\n", len(event.ChangedAssets), event.BuildTime)
return nil
}
struct MyReporter: Reporter {
func buildSuccess(_ event: BuildSuccess, options: Options) async throws {
print("✨ Rebuilt \(event.changedAssets.count) assets in \(event.buildTime)!")
}
}
Build failure
#The build failure event is emitted when a build completes with errors. It includes a list of diagnostics describing the errors. See Diagnostics for details.
import { Reporter } from "@parcel/plugin";
export default new Reporter({
buildFailure({ diagnostics }) {
console.log(`🚨 Build failed with ${diagnostics.length} errors.`);
},
});
impl Plugin for MyReporter {
fn build_failure(&self, event: &BuildFailure, _options: &Options) -> Result<(), Diagnostic> {
println!("🚨 Build failed with {} errors.", event.diagnostics.len());
Ok(())
}
}
func (r *MyReporter) BuildFailure(event *parcel.BuildFailure, _ *parcel.Options) error {
fmt.Printf("🚨 Build failed with %d errors.\n", event.Diagnostics.Len())
return nil
}
struct MyReporter: Reporter {
func buildFailure(_ event: BuildFailure, options: Options) async throws {
print("🚨 Build failed with \(event.diagnostics.count) errors.")
}
}
Logging
#All logging in Parcel is routed through Reporter plugins. The level of each log event is one of error, warn, info, or verbose. Each event includes either a message string, or a list of diagnostics, which provide detail about the context of the log. Only messages allowed by the --log-level CLI option are sent to reporters.
import { Reporter } from "@parcel/plugin";
export default new Reporter({
log({ level, message, diagnostics }) {
let messages =
message != null ? [message] : diagnostics.map((d) => d.message);
for (let message of messages) {
sendToLogService(level, message);
}
},
});
impl Plugin for MyReporter {
fn log(&self, event: &Log, _options: &Options) -> Result<(), Diagnostic> {
let messages: Vec<String> = match event.message {
Some(message) => vec![message.to_string()],
None => event.diagnostics.iter().flat_map(|d| d.iter()).map(|d| d.message()).collect(),
};
for message in messages {
send_to_log_service(event.level, &message);
}
Ok(())
}
}
func (r *MyReporter) Log(event *parcel.Log, _ *parcel.Options) error {
var messages []string
if event.Diagnostics == nil {
messages = []string{event.Message}
} else {
for _, d := range event.Diagnostics.All() {
messages = append(messages, d.Message())
}
}
for _, message := range messages {
sendToLogService(event.Level, message)
}
return nil
}
struct MyReporter: Reporter {
func log(_ event: Log, options: Options) async throws {
let messages: [String]
switch event.message {
case .text(let message):
messages = [message]
case .diagnostics(let diagnostics):
messages = diagnostics.map(\.message)
@unknown default:
messages = []
}
for message in messages {
sendToLogService(event.level, message)
}
}
}
Relevant API
#The API reference below covers JavaScript plugins. For native plugins, see the Rust, Go, and Swift SDKs.
ReporterContext packages-v3/plugin/src/types.ts:817
Passed to every reporter method alongside the event's own fields.
type ReporterContext<ConfigType> = {
readonly config: ConfigType;
readonly options: PluginOptions;
}
Referenced by:
BuildFailureEvent, BuildStartEvent, BuildSuccessEvent, LogEventBuildStartEvent packages-v3/plugin/src/types.ts:826
The build just started.
Type
type BuildStartEvent<ConfigType> = ReporterContext<ConfigType>;
Referenced by:
ReporterBuildSuccessEvent packages-v3/plugin/src/types.ts:832
The build was successful.
Property Descriptions
buildTime:The duration of the build, in milliseconds.
changedAssets:The assets transformed by this build. On a full build, that is every asset.
Type
type BuildSuccessEvent<ConfigType> = ReporterContext<ConfigType> & {
readonly bundleGraph: BundleGraph;
readonly buildTime: number;
readonly changedAssets: Array<Asset>;
};
Referenced by:
ReporterBuildFailureEvent packages-v3/plugin/src/types.ts:844
The build failed.
Type
type BuildFailureEvent<ConfigType> = ReporterContext<ConfigType> & {
readonly diagnostics: Array<DiagnosticOptions>;
};
Referenced by:
ReporterLogEvent packages-v3/plugin/src/types.ts:852
A message was logged, either as text or as diagnostics.
Type
type LogEvent<ConfigType> = ReporterContext<ConfigType> & {
readonly level: Exclude<LogLevel, 'none'>;
} & (
| {
readonly message: string;
readonly diagnostics?: undefined;
}
| {
readonly message?: undefined;
readonly diagnostics: Array<DiagnosticOptions>;
}
);
Referenced by:
ReporterReporter packages-v3/plugin/src/types.ts:871
A reporter must implement at least one of these methods.
config is the configuration given for the plugin in .parcelrc, if any.
type Reporter<ConfigType> = {
buildStart?: (event: BuildStartEvent<ConfigType>) => Async<void>;
buildSuccess?: (event: BuildSuccessEvent<ConfigType>) => Async<void>;
buildFailure?: (event: BuildFailureEvent<ConfigType>) => Async<void>;
log?: (event: LogEvent<ConfigType>) => Async<void>;
}