v 0.1.49

Creating Custom Processors

Processors in Ecopages are plugins that handle file transformations during the build process. This guide will show you how to create your own processor.

Basic Structure

A processor extends the Processor abstract class from @ecopages/core:

import { Processor } from '@ecopages/core/plugins/processor';
import type { BunPlugin } from 'bun';
 
class CustomProcessor extends Processor {
	// Plugins used during build time
	buildPlugins: BunPlugin[] = [];
 
	// Plugins used during runtime
	plugins: BunPlugin[] = [];
 
	constructor(config: ProcessorConfig) {
		super({
			name: 'custom-processor',
			watch: {
				paths: ['src/custom'],
				extensions: ['.custom'],
			},
			...config,
		});
	}
 
	async setup(): Promise<void> {
		// Initialize resources, create cache directories, etc.
	}
 
	async process(input: unknown): Promise<unknown> {
		// Transform the input
		return input;
	}
 
	async teardown(): Promise<void> {
		// Cleanup resources
	}
}

Processor Lifecycle

  1. Setup: Called when the processor is initialized
  2. Process: Called for each file that matches the processor's configuration
  3. Teardown: Called when the processor is being shut down

Working with Cache

Processors have built-in caching capabilities:

class CustomProcessor extends Processor {
	async process(input: string): Promise<string> {
		const cacheKey = 'my-cache-key';
 
		// Try to read from cache first
		const cached = await this.readCache<string>(cacheKey);
		if (cached) return cached;
 
		// Process and cache result
		const result = await someExpensiveOperation(input);
		await this.writeCache(cacheKey, result);
 
		return result;
	}
}

Adding Bun Plugins

You can add Bun plugins for both build time and runtime:

import { plugin } from 'bun';
 
class CustomProcessor extends Processor {
	buildPlugins = [
		plugin({
			name: 'custom-build-plugin',
			setup(build) {
				// Build-time plugin configuration
			},
		}),
	];
 
	plugins = [
		plugin({
			name: 'custom-runtime-plugin',
			setup(build) {
				// Runtime plugin configuration
			},
		}),
	];
}

File Watching

Configure file watching for development mode:

class CustomProcessor extends Processor {
	constructor() {
		super({
			name: 'custom-processor',
			watch: {
				paths: ['src/custom'],
				extensions: ['.custom'],
				onChange: async ({ path, bridge }) => {
					// Handle file changes
					// bridge.reload() or bridge.cssUpdate(path)
				},
				onDelete: async ({ path, bridge }) => {
					// Handle file deletions
				},
			},
		});
	}
}

Using the Processor

Register your processor in the Ecopages configuration:

import { ConfigBuilder } from '@ecopages/core';
 
const customProcessor = new CustomProcessor({
	// processor options
});
 
const config = await new ConfigBuilder().addProcessor(customProcessor).build();

Communicating with the Browser (ClientBridge)

Processors can broadcast events to connected browser clients for live updates (e.g., CSS hot reload) using the bridge provided in the onChange callback:

class StyleProcessor extends Processor {
	constructor() {
		super({
			name: 'style-processor',
			watch: {
				paths: ['src/styles'],
				extensions: ['.css'],
				onChange: async ({ path, bridge }) => {
					await this.processFile(path, bridge);
				},
			},
		});
	}
 
	private async processFile(filePath: string, bridge: ClientBridge) {
		if (!this.context) return;
 
		// Process and write the file...
		const processed = await this.process(await Bun.file(filePath).text());
		await Bun.write(outputPath, processed);
 
		// Broadcast CSS update to connected browsers
		// This will trigger a hot reload of the stylesheet
		bridge.cssUpdate(filePath);
 
		// Or trigger a full reload if needed:
		// bridge.reload();
 
		// Or send a custom error:
		// bridge.error("Processing failed");
	}
}

The ClientBridge provides several utility methods:

Best Practices

  1. Use meaningful names for your processors
  2. Implement proper error handling
  3. Cache expensive operations
  4. Clean up resources in teardown
  5. Follow TypeScript best practices
  6. Document your processor's API
  7. Use bridge for live updates instead of full reloads when possible