or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

file-watching.mdindex.mdinstance-management.mdnotifications-ui.mdplugins.mdserver-proxy.mdsynchronization.md
tile.json

plugins.mddocs/

Plugin System

Browser-sync features an extensible plugin architecture that allows developers to add custom functionality, integrate with build tools, and extend core capabilities. Plugins can hook into various lifecycle events and modify browser-sync behavior.

Capabilities

Plugin Registration

Register and load plugins to extend browser-sync functionality.

/**
 * Register a plugin with browser-sync
 * @param name - Plugin identifier name
 * @param plugin - Plugin module or object
 * @param callback - Optional callback for error handling
 */
use(name: string, plugin: BrowserSyncPlugin | PluginFunction, callback?: (error?: Error) => void): void;

/**
 * Plugin configuration in browser-sync options
 */
plugins?: string[] | PluginConfig[];

interface PluginConfig {
    /** Plugin module name or path */
    module: string;
    /** Plugin configuration options */
    options?: any;
}

/**
 * Standard plugin interface
 */
interface BrowserSyncPlugin {
    /** 
     * Main plugin function called during initialization
     * @param options - Plugin options passed during registration
     * @param bs - Browser-sync instance
     * @returns Plugin API or undefined
     */
    plugin(options: any, bs: BrowserSyncInstance): any;
    /** Optional plugin name */
    pluginName?: string;
    /** Optional plugin hooks */
    hooks?: PluginHooks;
}

type PluginFunction = (options: any, bs: BrowserSyncInstance) => any;

Usage Examples:

const browserSync = require('browser-sync');

// Register plugin after initialization
const bs = browserSync.create();
bs.init({ server: './app' });

// Register a simple plugin
bs.use('my-plugin', function(options, bs) {
    console.log('Plugin loaded with options:', options);
    
    // Plugin logic here
    bs.emitter.on('file:changed', function(file) {
        console.log('Plugin detected file change:', file);
    });
});

// Register plugin with configuration
bs.use('custom-logger', {
    plugin: function(options, bs) {
        const logLevel = options.level || 'info';
        
        bs.emitter.on('service:running', function(data) {
            if (logLevel === 'debug') {
                console.log('Service started:', data);
            }
        });
    }
}, function(err) {
    if (err) console.error('Plugin registration failed:', err);
});

// Load plugins via configuration
browserSync({
    server: './app',
    plugins: [
        'bs-html-injector',
        {
            module: 'bs-eslint-message',
            options: {
                formatter: 'compact'
            }
        }
    ]
});

Creating Custom Plugins

Build custom plugins to extend browser-sync functionality for specific needs.

/**
 * Plugin development interfaces
 */
interface PluginHooks {
    /** Called when client connects */
    'client:connected'?: (client: any) => void;
    /** Called on file changes */
    'file:changed'?: (file: string) => void;
    /** Called before browser reload */
    'browser:reload'?: () => void;
    /** Called on service start */
    'service:running'?: (data: any) => void;
}

interface BrowserSyncInstance {
    /** Event emitter for listening to browser-sync events */
    emitter: EventEmitter;
    /** Socket.IO namespace for client communication */
    sockets: any;
    /** Get configuration option */
    getOption(key: string): any;
    /** Reload browsers */
    reload(files?: any): void;
    /** Send notification */
    notify(message: string, timeout?: number): void;
}

Plugin Development Examples:

// Simple logging plugin
const myLoggerPlugin = {
    pluginName: 'MyLogger',
    plugin: function(options, bs) {
        const prefix = options.prefix || '[MyLogger]';
        
        // Listen to various events
        bs.emitter.on('file:changed', function(file) {
            console.log(`${prefix} File changed: ${file}`);
        });
        
        bs.emitter.on('browser:reload', function() {
            console.log(`${prefix} Browser reloading...`);
        });
        
        bs.emitter.on('client:connected', function(client) {
            console.log(`${prefix} Client connected: ${client.id}`);
            bs.notify(`New client connected: ${client.id}`);
        });
        
        // Return plugin API (optional)
        return {
            log: function(message) {
                console.log(`${prefix} ${message}`);
            }
        };
    }
};

// Register the plugin
bs.use('my-logger', myLoggerPlugin, { prefix: '[DEV]' });

// Build process integration plugin
const buildIntegrationPlugin = {
    plugin: function(options, bs) {
        const buildCommand = options.command || 'npm run build';
        
        let isBuilding = false;
        
        bs.emitter.on('file:changed', function(file) {
            if (isBuilding) return;
            
            // Check if file requires build
            if (file.match(/\.(scss|ts|jsx?)$/)) {
                isBuilding = true;
                bs.notify('Building...', 1000);
                
                const { exec } = require('child_process');
                exec(buildCommand, (error, stdout, stderr) => {
                    isBuilding = false;
                    
                    if (error) {
                        bs.notify(`Build failed: ${error.message}`, 5000);
                    } else {
                        bs.notify('Build complete');
                        bs.reload();
                    }
                });
            }
        });
    }
};

// API testing plugin
const apiTestPlugin = {
    plugin: function(options, bs) {
        const testEndpoint = options.endpoint || '/api/test';
        
        // Add middleware for API testing
        const middleware = function(req, res, next) {
            if (req.url === testEndpoint) {
                res.setHeader('Content-Type', 'application/json');
                res.end(JSON.stringify({
                    status: 'ok',
                    timestamp: Date.now(),
                    userAgent: req.headers['user-agent']
                }));
            } else {
                next();
            }
        };
        
        // Return middleware to be used
        return {
            middleware: middleware
        };
    }
};

Popular Plugins

Common browser-sync plugins for various development scenarios.

/**
 * HTML injection plugin for faster HTML updates
 */
interface HtmlInjectorPlugin {
    files: string | string[];
    restrictions?: string[];
}

/**
 * ESLint integration plugin for code quality notifications
 */
interface EslintMessagePlugin {
    formatter?: string;
    eslintrc?: string;
}

/**
 * Compression plugin for gzip/deflate responses
 */
interface CompressionPlugin {
    level?: number;
    threshold?: number;
}

Popular Plugin Examples:

const browserSync = require('browser-sync');

// HTML Injector - inject HTML changes without full reload
browserSync({
    server: './app',
    plugins: [
        {
            module: 'bs-html-injector',
            options: {
                files: './app/**/*.html',
                restrictions: ['.navbar'] // Don't inject changes to navbar
            }
        }
    ]
});

// ESLint integration
browserSync({
    server: './app',
    plugins: [
        {
            module: 'bs-eslint-message',
            options: {
                formatter: 'compact'
            }
        }
    ]
});

// Multiple plugins with different configurations
browserSync({
    server: './app',
    plugins: [
        'bs-html-injector', // Default configuration
        {
            module: 'bs-console-qrcode', // QR code for mobile access
            options: {
                ui: false // Don't show QR for UI
            }
        },
        {
            module: 'bs-latency',
            options: {
                latency: 100 // Simulate 100ms latency
            }
        }
    ]
});

Plugin Lifecycle and Hooks

Understanding when and how plugins are executed in the browser-sync lifecycle.

/**
 * Plugin lifecycle events
 */
interface PluginLifecycle {
    /** Called when browser-sync initializes */
    'init': (bs: BrowserSyncInstance) => void;
    /** Called when server starts */  
    'service:running': (data: ServiceData) => void;
    /** Called when client connects */
    'client:connected': (client: ClientData) => void;
    /** Called when file changes */
    'file:changed': (file: string, event: string) => void;
    /** Called before reload */
    'browser:reload': (data?: any) => void;
    /** Called on service exit */
    'service:exit': () => void;
}

interface ServiceData {
    port: number;
    urls: {
        local: string;
        external: string;
        ui: string;
    };
}

interface ClientData {
    id: string;
    address: string;
    userAgent: string;
}

Lifecycle Hook Examples:

const lifecyclePlugin = {
    plugin: function(options, bs) {
        // Initialization hook
        console.log('Plugin initializing...');
        
        // Service hooks
        bs.emitter.on('service:running', function(data) {
            console.log('Service started on:', data.urls.local);
            
            // Send welcome notification
            setTimeout(() => {
                bs.notify('Development server ready!', 3000);
            }, 1000);
        });
        
        // Client connection hooks
        bs.emitter.on('client:connected', function(client) {
            console.log(`New client: ${client.id} from ${client.address}`);
            
            // Track client for analytics
            analytics.track('client_connected', {
                userAgent: client.userAgent,
                timestamp: Date.now()
            });
        });
        
        // File change hooks
        bs.emitter.on('file:changed', function(file, event) {
            console.log(`File ${event}: ${file}`);
            
            // Custom processing based on file type
            const ext = path.extname(file);
            switch (ext) {
                case '.css':
                    // CSS-specific handling
                    console.log('Processing CSS file...');
                    break;
                case '.js':
                    // JavaScript-specific handling
                    console.log('Processing JS file...');
                    break;
            }
        });
        
        // Reload hooks
        bs.emitter.on('browser:reload', function() {
            console.log('Browsers reloading...');
            
            // Clear caches, update counters, etc.
            performance.mark('reload-start');
        });
        
        // Cleanup hooks
        bs.emitter.on('service:exit', function() {
            console.log('Plugin cleaning up...');
            
            // Clean up resources, save state, etc.
            cleanup();
        });
    }
};

Advanced Plugin Patterns

Advanced patterns for creating sophisticated browser-sync plugins.

Middleware Integration:

const middlewarePlugin = {
    plugin: function(options, bs) {
        // Create custom middleware
        const customMiddleware = function(req, res, next) {
            // Add custom headers
            res.setHeader('X-Dev-Server', 'BrowserSync');
            
            // Log requests
            console.log(`${req.method} ${req.url}`);
            
            // Custom routing
            if (req.url.startsWith('/api/')) {
                handleApiRequest(req, res);
            } else {
                next();
            }
        };
        
        // Return middleware for browser-sync to use
        return {
            middleware: customMiddleware
        };
    }
};

Socket Communication:

const socketPlugin = {
    plugin: function(options, bs) {
        // Listen for custom events from clients
        bs.sockets.on('connection', function(socket) {
            socket.on('custom:ping', function(data) {
                console.log('Received ping from client:', data);
                
                // Respond to client
                socket.emit('custom:pong', {
                    message: 'Server received your ping',
                    timestamp: Date.now()
                });
            });
            
            socket.on('custom:sync-data', function(data) {
                // Broadcast to all clients
                bs.sockets.emit('custom:data-update', data);
            });
        });
        
        // Send periodic updates to clients
        setInterval(() => {
            bs.sockets.emit('custom:heartbeat', {
                timestamp: Date.now(),
                uptime: process.uptime()
            });
        }, 30000);
    }
};