Разработка Плагинов Rollup

Примеры разработки плагинов Rollup, включая пользовательские плагины, трансформации и паттерны сборки

💻 Gulp Basic Tasks javascript

🟢 simple ⭐⭐⭐⭐

Essential Gulp tasks for modern web development including file processing, watching, and building

⏱️ 45 min 🏷️ rollup, plugins, advanced
Prerequisites: Rollup basics, JavaScript AST, Plugin architecture
// Gulp Basic Tasks Setup
// Modern Gulp 4.x configuration for web development workflows

// ===== package.json =====
{
  "name": "my-gulp-project",
  "version": "1.0.0",
  "description": "Modern web application using Gulp for task automation",
  "main": "index.js",
  "scripts": {
    "dev": "gulp dev",
    "build": "gulp build",
    "watch": "gulp watch",
    "clean": "gulp clean",
    "serve": "gulp serve",
    "test": "gulp test",
    "lint": "gulp lint",
    "deploy": "gulp deploy"
  },
  "devDependencies": {
    "gulp": "^4.0.2",
    "gulp-cli": "^2.3.0",
    "gulp-sass": "^5.1.0",
    "gulp-postcss": "^9.0.1",
    "autoprefixer": "^10.4.0",
    "cssnano": "^5.1.0",
    "gulp-terser": "^2.1.0",
    "gulp-babel": "^8.0.0",
    "@babel/core": "^7.20.0",
    "@babel/preset-env": "^7.20.0",
    "@babel/preset-react": "^7.18.0",
    "gulp-imagemin": "^8.0.0",
    "gulp-rename": "^2.0.0",
    "gulp-uglify": "^3.0.2",
    "gulp-clean-css": "^4.3.0",
    "gulp-concat": "^2.6.1",
    "gulp-sourcemaps": "^3.0.0",
    "gulp-eslint": "^6.0.0",
    "gulp-stylelint": "^13.0.0",
    "gulp-htmlmin": "^5.0.1",
    "gulp-file-include": "^2.3.0",
    "gulp-replace": "^1.1.4",
    "gulp-size": "^4.0.0",
    "gulp-brotli": "^2.0.2",
    "gulp-zip": "^5.1.0",
    "gulp-plumber": "^1.2.1",
    "gulp-if": "^3.0.0",
    "gulp-notify": "^4.0.0",
    "browser-sync": "^2.27.0",
    "del": "^7.0.0",
    "through2": "^4.0.2",
    "vinyl-buffer": "^1.0.1",
    "vinyl-source-stream": "^2.0.0",
    "node-sass": "^8.0.0",
    "tailwindcss": "^3.2.0",
    "postcss": "^8.4.0",
    "webpack-stream": "^7.0.0",
    "dotenv": "^16.0.0",
    "cross-env": "^7.0.3"
  }
}

// ===== gulpfile.js =====
const { src, dest, watch, series, parallel, task } = require('gulp');
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const notify = require('gulp-notify');
const sourcemaps = require('gulp-sourcemaps');
const rename = require('gulp-rename');
const replace = require('gulp-replace');
const size = require('gulp-size');
const del = require('del');

// Load environment variables
require('dotenv').config();

// Configuration
const config = {
    src: {
        html: 'src/**/*.html',
        css: 'src/scss/**/*.scss',
        js: 'src/js/**/*.js',
        images: 'src/images/**/*',
        fonts: 'src/fonts/**/*',
        assets: 'src/assets/**/*'
    },
    build: {
        html: 'dist',
        css: 'dist/css',
        js: 'dist/js',
        images: 'dist/images',
        fonts: 'dist/fonts',
        assets: 'dist'
    },
    isProduction: process.env.NODE_ENV === 'production',
    isDevelopment: process.env.NODE_ENV === 'development'
};

// Error handler
function errorHandler(err) {
    notify.onError({
        title: 'Gulp Error',
        message: '<%= error.message %>'
    })(err);
    this.emit('end');
}

// Clean build directory
function clean() {
    return del(['dist/**/*', '!dist/.gitkeep']);
}

// HTML tasks
const htmlmin = require('gulp-htmlmin');
const fileInclude = require('gulp-file-include');

function html() {
    return src(config.src.html)
        .pipe(plumber({ errorHandler }))
        .pipe(fileInclude({
            prefix: '@@',
            basepath: 'src/'
        }))
        .pipe(gulpIf(config.isProduction, htmlmin({
            collapseWhitespace: true,
            removeComments: true,
            removeRedundantAttributes: true,
            removeScriptTypeAttributes: true,
            removeStyleLinkTypeAttributes: true,
            useShortDoctype: true,
            minifyCSS: true,
            minifyJS: true
        })))
        .pipe(replace('%%VERSION%%', process.env.npm_package_version || '1.0.0'))
        .pipe(gulpIf(config.isProduction, size({ title: 'HTML:', showFiles: true })))
        .pipe(dest(config.build.html));
}

// CSS/SCSS tasks
const sass = require('gulp-sass')(require('node-sass'));
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const cleanCSS = require('gulp-clean-css');

function styles() {
    const processors = [
        autoprefixer(),
        gulpIf(config.isProduction, cssnano())
    ];

    return src(config.src.css)
        .pipe(plumber({ errorHandler }))
        .pipe(gulpIf(config.isDevelopment, sourcemaps.init()))
        .pipe(sass({
            outputStyle: config.isProduction ? 'compressed' : 'expanded',
            includePaths: ['node_modules']
        }).on('error', sass.logError))
        .pipe(postcss(processors))
        .pipe(gulpIf(config.isProduction, cleanCSS()))
        .pipe(rename({ suffix: '.min' }))
        .pipe(gulpIf(config.isDevelopment, sourcemaps.write('.')))
        .pipe(gulpIf(config.isProduction, size({ title: 'CSS:', showFiles: true })))
        .pipe(dest(config.build.css));
}

// JavaScript tasks
const babel = require('gulp-babel');
const terser = require('gulp-terser');
const concat = require('gulp-concat');

function scripts() {
    return src(config.src.js)
        .pipe(plumber({ errorHandler }))
        .pipe(gulpIf(config.isDevelopment, sourcemaps.init()))
        .pipe(babel({
            presets: [
                ['@babel/preset-env', {
                    targets: {
                        browsers: ['last 2 versions', 'not dead']
                    },
                    modules: false
                }]
            ]
        }))
        .pipe(gulpIf(config.isProduction, concat('bundle.min.js')))
        .pipe(gulpIf(config.isProduction, terser({
            compress: {
                drop_console: true,
                drop_debugger: true
            }
        })))
        .pipe(gulpIf(config.isDevelopment, sourcemaps.write('.')))
        .pipe(gulpIf(config.isProduction, size({ title: 'JavaScript:', showFiles: true })))
        .pipe(dest(config.build.js));
}

// Vendor JavaScript (libraries from node_modules)
function vendorScripts() {
    const vendorFiles = [
        'node_modules/jquery/dist/jquery.min.js',
        'node_modules/bootstrap/dist/js/bootstrap.bundle.min.js'
    ];

    return src(vendorFiles)
        .pipe(concat('vendor.min.js'))
        .pipe(gulpIf(config.isProduction, terser()))
        .pipe(dest(config.build.js));
}

// Image optimization
const imagemin = require('gulp-imagemin');

function images() {
    return src(config.src.images)
        .pipe(plumber({ errorHandler }))
        .pipe(imagemin([
            imagemin.gifsicle({ interlaced: true }),
            imagemin.mozjpeg({ quality: 80, progressive: true }),
            imagemin.optipng({ optimizationLevel: 5 }),
            imagemin.svgo({
                plugins: [
                    { removeViewBox: false },
                    { collapseGroups: true }
                ]
            })
        ]))
        .pipe(gulpIf(config.isProduction, size({ title: 'Images:', showFiles: true })))
        .pipe(dest(config.build.images));
}

// Font handling
function fonts() {
    return src(config.src.fonts)
        .pipe(plumber({ errorHandler }))
        .pipe(dest(config.build.fonts));
}

// Other assets
function assets() {
    return src(config.src.assets)
        .pipe(plumber({ errorHandler }))
        .pipe(dest(config.build.assets));
}

// Code quality tasks
const eslint = require('gulp-eslint');
const stylelint = require('gulp-stylelint');

function lintJS() {
    return src(config.src.js)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
}

function lintCSS() {
    return src(config.src.css)
        .pipe(stylelint({
            reporters: [
                { formatter: 'string', console: true }
            ]
        }));
}

// Development server
const browserSync = require('browser-sync').create();

function serve() {
    browserSync.init({
        server: 'dist',
        port: 3000,
        open: true,
        notify: false,
        ghostMode: false,
        files: [
            'dist/css/**/*.css',
            'dist/js/**/*.js',
            'dist/**/*.html'
        ]
    });

    watch(config.src.html, html);
    watch(config.src.css, styles);
    watch(config.src.js, scripts);
    watch(config.src.images, images);
    watch(config.src.fonts, fonts);
    watch(config.src.assets, assets);
}

// Build tasks
const build = series(clean, parallel(html, styles, scripts, vendorScripts, images, fonts, assets));

// Development task
const dev = series(clean, parallel(html, styles, scripts, vendorScripts, images, fonts, assets), serve);

// Production build
function production() {
    process.env.NODE_ENV = 'production';
    return build();
}

// Watch task
function watchFiles() {
    watch(config.src.html, html);
    watch(config.src.css, styles);
    watch(config.src.js, scripts);
    watch(config.src.images, images);
    watch(config.src.fonts, fonts);
    watch(config.src.assets, assets);
}

// Export tasks
exports.clean = clean;
exports.html = html;
exports.styles = styles;
exports.scripts = scripts;
exports.vendorScripts = vendorScripts;
exports.images = images;
exports.fonts = fonts;
exports.assets = assets;
exports.lint = parallel(lintJS, lintCSS);
exports.build = build;
exports.dev = dev;
exports.production = production;
exports.watch = watchFiles;
exports.serve = serve;
exports.default = dev;

// ===== gulpfile.config.js =====
module.exports = {
    src: {
        root: 'src',
        html: 'src/**/*.html',
        css: 'src/scss/**/*.scss',
        js: 'src/js/**/*.js',
        ts: 'src/ts/**/*.ts',
        jsx: 'src/jsx/**/*.jsx',
        tsx: 'src/tsx/**/*.tsx',
        images: 'src/images/**/*',
        fonts: 'src/fonts/**/*',
        icons: 'src/icons/**/*',
        data: 'src/data/**/*',
        templates: 'src/templates/**/*'
    },
    build: {
        root: 'dist',
        html: 'dist',
        css: 'dist/css',
        js: 'dist/js',
        vendor: 'dist/vendor',
        images: 'dist/images',
        fonts: 'dist/fonts',
        icons: 'dist/icons',
        data: 'dist/data',
        templates: 'dist/templates'
    },
    temp: {
        root: '.tmp',
        styles: '.tmp/styles'
    },
    nodeModules: 'node_modules',
    browsersync: {
        server: {
            baseDir: ['dist'],
            index: 'index.html'
        },
        port: 3000,
        open: true,
        notify: true,
        ghostMode: {
            clicks: true,
            scroll: true,
            forms: true
        }
    },
    plumber: {
        errorHandler: function(err) {
            notify.onError({
                title: 'Gulp Error',
                message: '<%= error.message %>',
                sound: 'Beep'
            })(err);
            this.emit('end');
        }
    },
    autoprefixer: {
        overrideBrowserslist: ['last 2 versions', 'not dead'],
        cascade: true
    },
    sass: {
        outputStyle: 'expanded',
        includePaths: ['node_modules']
    },
    esLint: {
        configFile: '.eslintrc.json',
        failAfterError: false
    },
    styleLint: {
        configFile: '.stylelintrc.json',
        failAfterError: false
    },
    imagemin: {
        optimizationLevel: 5,
        progressive: true,
        interlaced: true,
        multipass: true
    },
    htmlmin: {
        collapseWhitespace: true,
        removeComments: true,
        removeRedundantAttributes: true,
        removeScriptTypeAttributes: true,
        removeStyleLinkTypeAttributes: true,
        useShortDoctype: true,
        minifyCSS: true,
        minifyJS: true,
        processConditionalComments: true
    },
    terser: {
        compress: {
            drop_console: true,
            drop_debugger: true,
            collapse_vars: true,
            reduce_vars: true
        },
        mangle: true,
        output: {
            comments: false
        }
    },
    cleanCSS: {
        level: 2,
            return Promise.resolve([file]);
        }

        return Promise.resolve(file);
    }

    async process(bundleGraph) {
        const outputOptions = this.options;

        // Store bundle graph for later use
        this.bundleGraph = bundleGraph;

        // Run original bundling
        const result = await this.defaultBundler.bundle(bundleGraph, outputOptions);

        // Run post-processing
        await this.postProcess(result, bundleGraph);

        return result;
    }

    async postProcess(bundleResult, bundleGraph) {
        // Additional processing after bundling
        console.log('Running post-processing...');

        // Example: Generate statistics
        const stats = await this.generateStats(bundleGraph);
        this.emit('buildStats', stats);
    }

    async generateStats(bundleGraph) {
        const bundles = bundleGraph.getBundles();
        const stats = {
            bundleCount: bundles.length,
            totalSize: 0,
            bundles: []
        };

        bundles.forEach(bundle => {
            const size = this.getBundleSize(bundle);
            stats.totalSize += size;

            stats.bundles.push({
                name: bundle.getEntryAssets()[0]?.filePath || 'unknown',
                size,
                type: bundle.type
            });
        });

        return stats;
    }

    getBundleSize(bundle) {
        let size = 0;
        bundle.getEntryAssets().forEach(asset => {
            size += asset.stats.size;
        });
        return size;
    }
} catch (error) {
    return originalBundler;
}

// Add catch-all to prevent fatal errors
} else {
    console.warn('Bundler not found in context, skipping plugin');
}

// Ensure we always return the original bundler
return originalBundler;
} catch (error) {
    return originalBundler;
} finally {
    // Reset error if it was thrown
    if (originalBundler) {
        return originalBundler;
    }
}

// Final fallback
return originalBundler || class MockBundler {
    async bundle() {
        console.warn('Mock bundler used');
    }
};
}

module.exports = bundlerWrapper;

// ===== PLUGIN ENHANCEMENT =====

// parcel-plugin-enhancer.js
const { promises: fs } = require('fs');

class PluginEnhancer {
    constructor() {
        this.enhancements = new Map();
        this.middlewares = [];
    }

    enhance(pluginName, enhancer) {
        if (!this.enhancements.has(pluginName)) {
            this.enhancements.set(pluginName, []);
        }
        this.enhancements.get(pluginName).push(enhancer);
    }

    addMiddleware(middleware) {
        this.middlewares.push(middleware);
    }

    async applyEnhancements(plugin, pluginName) {
        const enhancements = this.enhancements.get(pluginName) || [];
        let enhancedPlugin = plugin;

        for (const enhancer of enhancements) {
            enhancedPlugin = await enhancer(enhancedPlugin);
        }

        // Apply middlewares
        for (const middleware of this.middlewares) {
            enhancedPlugin = await middleware(enhancedPlugin, pluginName);
        }

        return enhancedPlugin;
    }
}

const enhancer = new PluginEnhancer();

// Add common enhancements
enhancer.enhance('@parcel/transformer-js', (transformer) => {
    return {
        ...transformer,
        transformWithEnhancements: async (asset) => {
            const result = await transformer.transform(asset);

            // Add enhancement features
            if (result.code) {
                // Add source mapping support
                result.code += `\n// Enhanced by parcel-plugin-optimizer`;
            }

            return result;
        }
    };
});

// Add middleware
enhancer.addMiddleware(async (plugin, pluginName) => {
    if (typeof plugin === 'function') {
        return async (...args) => {
            const result = await plugin(...args);

            // Log plugin usage
            console.log(`Using enhanced plugin: ${pluginName}`);

            return result;
        };
    }

    return plugin;
});

module.exports = enhancer;

// ===== REAL-TIME PLUGIN SYSTEM =====

// parcel-plugin-system.js
class ParcelPluginSystem {
    constructor() {
        this.plugins = new Map();
        this.hooks = new Map();
        this.config = new Map();
        this.status = 'idle';
        this.metrics = {
            pluginsLoaded: 0,
            hooksExecuted: 0,
            errors: 0
        };
    }

    // Plugin registration
    registerPlugin(name, plugin) {
        if (this.plugins.has(name)) {
            throw new Error(`Plugin ${name} already registered`);
        }

        this.plugins.set(name, {
            name,
            plugin,
            status: 'registered',
            loadedAt: null,
            error: null
        });

        this.emit('pluginRegistered', { name, plugin });
        return this;
    }

    // Load all registered plugins
    async loadPlugins() {
        this.status = 'loading';
        const loadPromises = Array.from(this.plugins.entries()).map(
            ([name, { plugin }]) => this.loadPlugin(name, plugin)
        );

        await Promise.allSettled(loadPromises);
        this.status = 'loaded';
        this.emit('pluginsLoaded', { count: this.metrics.pluginsLoaded });
    }

    async loadPlugin(name, plugin) {
        const pluginInfo = this.plugins.get(name);

        try {
            // Initialize plugin if it has init method
            if (typeof plugin.init === 'function') {
                await plugin.init(this);
            }

            pluginInfo.status = 'loaded';
            pluginInfo.loadedAt = Date.now();
            this.metrics.pluginsLoaded++;

            this.emit('pluginLoaded', { name });
        } catch (error) {
            pluginInfo.status = 'error';
            pluginInfo.error = error;
            this.metrics.errors++;

            this.emit('pluginError', { name, error });
        }
    }

    // Hook registration
    registerHook(hookName, handler, options = {}) {
        if (!this.hooks.has(hookName)) {
            this.hooks.set(hookName, []);
        }

        this.hooks.get(hookName).push({
            handler,
            options,
            id: Math.random().toString(36).substr(2, 9)
        });

        return this;
    }

    // Execute hooks
    async executeHook(hookName, context = {}) {
        const handlers = this.hooks.get(hookName) || [];
        const results = [];

        this.metrics.hooksExecuted++;

        for (const { handler, options } of handlers) {
            try {
                const result = await handler(context, this);

                if (options.stopPropagation && result === false) {
                    break;
                }

                results.push(result);
            } catch (error) {
                this.metrics.errors++;
                this.emit('hookError', { hookName, error });

                if (options.breakOnError) {
                    throw error;
                }
            }
        }

        return results;
    }

    // Configuration management
    setConfig(key, value) {
        this.config.set(key, value);
        this.emit('configChanged', { key, value });
    }

    getConfig(key) {
        return this.config.get(key);
    }

    // Event emission
    emit(event, data) {
        // Implement event emission
        console.log(`[PluginSystem] ${event}:`, data);
    }

    // Plugin unloading
    async unloadPlugin(name) {
        const pluginInfo = this.plugins.get(name);
        if (!pluginInfo) {
            throw new Error(`Plugin ${name} not found`);
        }

        try {
            // Call plugin cleanup if available
            if (pluginInfo.plugin && typeof pluginInfo.plugin.cleanup === 'function') {
                await pluginInfo.plugin.cleanup();
            }

            pluginInfo.status = 'unloaded';
            this.emit('pluginUnloaded', { name });
        } catch (error) {
            pluginInfo.error = error;
            this.emit('pluginUnloadError', { name, error });
        }
    }

    // Get plugin status
    getPluginStatus(name) {
        const pluginInfo = this.plugins.get(name);
        return pluginInfo ? pluginInfo.status : 'not_found';
    }

    // List all plugins
    listPlugins() {
        return Array.from(this.plugins.entries()).map(([name, info]) => ({
            name,
            status: info.status,
            error: info.error,
            loadedAt: info.loadedAt
        }));
    }

    // Performance metrics
    getMetrics() {
        return {
            ...this.metrics,
            status: this.status,
            pluginCount: this.plugins.size,
            hookCount: Array.from(this.hooks.values()).reduce((sum, hooks) => sum + hooks.length, 0)
        };
    }

    // Cleanup
    async cleanup() {
        this.status = 'cleaning';

        const cleanupPromises = Array.from(this.plugins.entries())
            .filter(([name, info]) => info.status === 'loaded')
            .map(([name]) => this.unloadPlugin(name));

        await Promise.allSettled(cleanupPromises);

        this.plugins.clear();
        this.hooks.clear();
        this.config.clear();

        this.status = 'cleaned';
        this.emit('systemCleanup');
    }
}

// Example plugin system usage
const pluginSystem = new ParcelPluginSystem();

// Register a sample plugin
pluginSystem.registerPlugin('samplePlugin', {
    init: async (system) => {
        console.log('Sample plugin initialized');
        system.setConfig('samplePlugin.enabled', true);
    },

    transform: async (asset) => {
        // Simple transformation
        if (asset.type === 'js') {
            asset.code += `\n// Processed by sample plugin`;
        }
        return asset;
    },

    cleanup: async () => {
        console.log('Sample plugin cleanup');
    }
});

// Register hooks
pluginSystem.registerHook('beforeBuild', async (context, system) => {
    console.log('Before build hook executed');
});

pluginSystem.registerHook('afterBuild', async (context, system) => {
    console.log('After build hook executed');
    console.log('Build metrics:', system.getMetrics());
});

module.exports = ParcelPluginSystem;

💻 Экосистема Плагинов Rollup javascript

🟡 intermediate ⭐⭐⭐⭐

Создание плагинов, которые интегрируются с более широкой экосистемой Rollup и общими паттернами

⏱️ 40 min 🏷️ rollup, plugins, ecosystem
Prerequisites: Rollup plugin development, JavaScript ecosystems, Build tools
// Rollup Plugin Ecosystem Integration
// Building plugins that work seamlessly with other Rollup plugins and tools

// ===== PLUGIN INTEROPERABILITY =====

// 1. Plugin Communication System
// plugin-communication.js
export class PluginCommunication {
    constructor() {
        this.channels = new Map();
        this.globalState = new Map();
    }

    // Subscribe to a channel
    subscribe(channel, callback) {
        if (!this.channels.has(channel)) {
            this.channels.set(channel, []);
        }
        this.channels.get(channel).push(callback);
    }

    // Publish to a channel
    publish(channel, data) {
        const subscribers = this.channels.get(channel) || [];
        subscribers.forEach(callback => callback(data));
    }

    // Set global state
    setState(key, value) {
        this.globalState.set(key, value);
        this.publish('stateChange', { key, value });
    }

    // Get global state
    getState(key) {
        return this.globalState.get(key);
    }
}

// 2. Plugin Registry System
// plugin-registry.js
export class PluginRegistry {
    constructor() {
        this.plugins = new Map();
        this.hooks = new Map();
        this.communication = new PluginCommunication();
    }

    // Register a plugin
    register(plugin) {
        if (!plugin.name) {
            throw new Error('Plugin must have a name');
        }

        if (this.plugins.has(plugin.name)) {
            throw new Error(`Plugin ${plugin.name} is already registered`);
        }

        // Initialize plugin hooks
        this.initializeHooks(plugin);

        // Store plugin
        this.plugins.set(plugin.name, plugin);

        // Notify other plugins
        this.communication.publish('pluginRegistered', { plugin });

        return this;
    }

    // Initialize plugin hooks
    initializeHooks(plugin) {
        const hookNames = [
            'buildStart', 'buildEnd', 'moduleParsed', 'resolveId',
            'load', 'transform', 'generateBundle', 'writeBundle',
            'renderChunk', 'renderStart', 'renderError'
        ];

        hookNames.forEach(hookName => {
            if (plugin[hookName]) {
                if (!this.hooks.has(hookName)) {
                    this.hooks.set(hookName, []);
                }
                this.hooks.get(hookName).push({
                    plugin: plugin.name,
                    handler: plugin[hookName].bind(plugin)
                });
            }
        });
    }

    // Execute hooks
    async executeHook(hookName, ...args) {
        const hooks = this.hooks.get(hookName) || [];
        const results = [];

        for (const { plugin, handler } of hooks) {
            try {
                const result = await handler(...args);
                results.push({ plugin, result });
            } catch (error) {
                console.error(`Error in hook ${hookName} for plugin ${plugin}:`, error);
                results.push({ plugin, error });
            }
        }

        return results;
    }
}

// 3. Plugin Lifecycle Manager
// lifecycle-manager.js
export class PluginLifecycleManager {
    constructor(registry) {
        this.registry = registry;
        this.phases = new Map();
    }

    // Register a phase
    registerPhase(name, plugins = []) {
        this.phases.set(name, plugins);
        return this;
    }

    // Execute a phase
    async executePhase(name, context = {}) {
        const phasePlugins = this.phases.get(name) || [];

        for (const pluginName of phasePlugins) {
            const plugin = this.registry.plugins.get(pluginName);
            if (plugin && plugin.phaseHandler) {
                await plugin.phaseHandler(name, context);
            }
        }
    }
}

// ===== INTEGRATION WITH COMMON PLUGINS =====

// 4. Alias Resolution Plugin
// alias-resolver-plugin.js
export default function aliasResolverPlugin(options = {}) {
    const { alias = {}, preserveSymlinks = false } = options;

    return {
        name: 'alias-resolver',

        resolveId(id, importer) {
            // Check if the ID matches any alias
            for (const [key, value] of Object.entries(alias)) {
                if (id === key || id.startsWith(key + '/')) {
                    const replacement = id.replace(key, value);
                    return this.resolve(replacement, importer, { preserveSymlinks });
                }
            }
            return null;
        },

        // Integrate with node-resolve
        async buildStart() {
            // Ensure node-resolve is available
            if (!this.getPluginInfo('node-resolve')) {
                this.warn('alias-resolver works best with @rollup/plugin-node-resolve');
            }
        }
    };
}

// 5. Virtual Modules Plugin
// virtual-modules-plugin.js
export default function virtualModulesPlugin(modules = {}) {
    const virtualModulePrefix = '\0virtual:';
    const virtualModules = new Map();

    // Initialize with provided modules
    Object.entries(modules).forEach(([id, content]) => {
        virtualModules.set(virtualModulePrefix + id, content);
    });

    return {
        name: 'virtual-modules',

        resolveId(id) {
            if (virtualModules.has(virtualModulePrefix + id)) {
                return virtualModulePrefix + id;
            }
            return null;
        },

        load(id) {
            if (virtualModules.has(id)) {
                return virtualModules.get(id);
            }
            return null;
        },

        // API to add virtual modules at runtime
        api: {
            addModule(id, content) {
                virtualModules.set(virtualModulePrefix + id, content);
            },
            hasModule(id) {
                return virtualModules.has(virtualModulePrefix + id);
            }
        }
    };
}

// 6. CSS Processing Plugin (with PostCSS integration)
// css-processor-plugin.js
import postcss from 'postcss';
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';

export default function cssProcessorPlugin(options = {}) {
    const {
        plugins = [autoprefixer, cssnano],
        inject = false,
        outputName = 'styles.css',
        minimize = process.env.NODE_ENV === 'production'
    } = options;

    let cssCode = '';
    const processedCSS = new Set();

    return {
        name: 'css-processor',

        transform(code, id) {
            if (!id.endsWith('.css') && !id.endsWith('.scss') && !id.endsWith('.sass')) {
                return null;
            }

            // Collect CSS code
            cssCode += code + '\n';
            return {
                code: 'export default null;',
                map: null
            };
        },

        buildEnd() {
            if (!cssCode.trim()) return;

            return postcss(minimize ? [...plugins, cssnano] : plugins)
                .process(cssCode, { from: undefined })
                .then(result => {
                    const processedResult = result.css;
                    processedCSS.add(processedResult);

                    if (inject) {
                        // Create CSS injector
                        const injector = `
(function() {
    var css = ${JSON.stringify(processedResult)};
    if (typeof document !== 'undefined') {
        var style = document.createElement('style');
        style.textContent = css;
        document.head.appendChild(style);
    }
})();
                        `;
                        this.emitFile({
                            type: 'chunk',
                            id: 'css-injector',
                            fileName: 'css-injector.js',
                            code: injector
                        });
                    } else {
                        // Emit CSS file
                        this.emitFile({
                            type: 'asset',
                            fileName: outputName,
                            source: processedResult
                        });
                    }
                })
                .catch(error => {
                    this.error(`CSS processing failed: ${error.message}`);
                });
        }
    };
}

// 7. Environment Configuration Plugin
// environment-config-plugin.js
export default function environmentConfigPlugin(options = {}) {
    const {
        environments = {},
        defaultEnv = 'development',
        configFile = '.rollup.env.js'
    } = options;

    let currentEnv = defaultEnv;
    let envConfig = {};

    return {
        name: 'environment-config',

        buildStart() {
            // Load environment configuration
            const fs = require('fs');
            const path = require('path');

            if (fs.existsSync(configFile)) {
                delete require.cache[require.resolve(path.resolve(configFile))];
                const userConfig = require(path.resolve(configFile));
                currentEnv = process.env.ROLLUP_ENV || userConfig.env || defaultEnv;
                envConfig = { ...userConfig, ...environments[currentEnv] };
            } else {
                currentEnv = process.env.ROLLUP_ENV || defaultEnv;
                envConfig = environments[currentEnv] || {};
            }

            console.log(`🌍 Using environment: ${currentEnv}`);
        },

        resolveId(id, importer) {
            // Handle environment-specific modules
            const envMatch = id.match(/^(.*)\.env\.(\w+)$/);
            if (envMatch) {
                const [, baseId, env] = envMatch;
                if (env === currentEnv) {
                    return this.resolve(baseId, importer);
                }
                return null;
            }
            return null;
        },

        transform(code, id) {
            // Replace environment variables in code
            const envRegex = /__ENV_([A-Z_]+)__|__CURRENT_ENV__/g;
            let hasReplacements = false;

            const result = code.replace(envRegex, (match, varName) => {
                hasReplacements = true;
                if (varName) {
                    return JSON.stringify(envConfig[varName.toLowerCase()] || process.env[varName] || '');
                }
                return JSON.stringify(currentEnv);
            });

            if (hasReplacements) {
                return {
                    code: result,
                    map: null
                };
            }
        },

        api: {
            getEnv() {
                return currentEnv;
            },
            getConfig() {
                return envConfig;
            },
            isDevelopment() {
                return currentEnv === 'development';
            },
            isProduction() {
                return currentEnv === 'production';
            }
        }
    };
}

// ===== ADVANCED ECOSYSTEM INTEGRATION =====

// 8. Plugin Dependency Manager
// dependency-manager-plugin.js
export default function dependencyManagerPlugin(options = {}) {
    const { dependencies = {}, autoInstall = false } = options;

    return {
        name: 'dependency-manager',

        buildStart() {
            // Check plugin dependencies
            for (const [pluginName, requiredVersion] of Object.entries(dependencies)) {
                const pluginInfo = this.getPluginInfo(pluginName);

                if (!pluginInfo) {
                    if (autoInstall) {
                        this.warn(`Installing missing plugin: ${pluginName}`);
                        // In a real implementation, you might want to install the plugin
                    } else {
                        this.error(`Required plugin not found: ${pluginName}`);
                    }
                } else {
                    // Version check (simplified)
                    const version = pluginInfo.version || '0.0.0';
                    if (!this.satisfiesVersion(version, requiredVersion)) {
                        this.warn(`Plugin version mismatch: ${pluginName} requires ${requiredVersion}, found ${version}`);
                    }
                }
            }
        },

        satisfiesVersion(current, required) {
            // Simplified version comparison
            const currentParts = current.split('.').map(Number);
            const requiredParts = required.split('.').map(Number);

            for (let i = 0; i < Math.max(currentParts.length, requiredParts.length); i++) {
                const currentPart = currentParts[i] || 0;
                const requiredPart = requiredParts[i] || 0;

                if (currentPart > requiredPart) return true;
                if (currentPart < requiredPart) return false;
            }
            return true;
        }
    };
}

// 9. Plugin Configuration Validator
// config-validator-plugin.js
export default function configValidatorPlugin(options = {}) {
    const {
        requiredOptions = [],
        optionValidators = {},
        strict = false
    } = options;

    return {
        name: 'config-validator',

        buildStart() {
            // Validate required options
            for (const option of requiredOptions) {
                if (!(option in this.options)) {
                    const message = `Required option '${option}' is missing`;
                    if (strict) {
                        this.error(message);
                    } else {
                        this.warn(message);
                    }
                }
            }

            // Run custom validators
            for (const [option, validator] of Object.entries(optionValidators)) {
                if (option in this.options) {
                    try {
                        const result = validator(this.options[option]);
                        if (!result) {
                            this.warn(`Option '${option}' failed validation`);
                        }
                    } catch (error) {
                        this.warn(`Validation error for option '${option}': ${error.message}`);
                    }
                }
            }
        }
    };
}

// 10. Bundle Optimization Pipeline
// optimization-pipeline-plugin.js
export default function optimizationPipelinePlugin(options = {}) {
    const {
        stages = [],
        parallel = false,
        timeout = 30000
    } = options;

    return {
        name: 'optimization-pipeline',

        generateBundle(outputOptions, bundle) {
            const pipeline = stages.map(stage => {
                if (typeof stage === 'string') {
                    return this.getOptimizationStage(stage);
                }
                return stage;
            });

            let optimizedBundle = { ...bundle };

            if (parallel) {
                // Run stages in parallel
                return Promise.all(
                    pipeline.map(stage => this.runOptimizationStage(stage, optimizedBundle))
                ).then(() => {
                    // Merge results
                    this.mergeOptimizationResults(optimizedBundle, pipeline);
                });
            } else {
                // Run stages sequentially
                return pipeline.reduce((promise, stage) => {
                    return promise.then(() => this.runOptimizationStage(stage, optimizedBundle));
                }, Promise.resolve());
            }
        },

        getOptimizationStage(name) {
            const stages = {
                'dedupe': this.dedupeStage.bind(this),
                'compress': this.compressStage.bind(this),
                'mangle': this.mangleStage.bind(this),
                'treeshake': this.treeshakeStage.bind(this),
                'optimize-imports': this.optimizeImportsStage.bind(this)
            };

            return stages[name] || (() => Promise.resolve());
        },

        runOptimizationStage(stage, bundle) {
            return new Promise((resolve, reject) => {
                const timer = setTimeout(() => {
                    reject(new Error('Optimization stage timeout'));
                }, timeout);

                try {
                    const result = stage(bundle);
                    if (result && typeof result.then === 'function') {
                        result.finally(() => clearTimeout(timer)).then(resolve).catch(reject);
                    } else {
                        clearTimeout(timer);
                        resolve();
                    }
                } catch (error) {
                    clearTimeout(timer);
                    reject(error);
                }
            });
        },

        // Optimization stage implementations
        dedupeStage(bundle) {
            // Remove duplicate modules
            const seen = new Set();
            const deduped = {};

            for (const [fileName, chunk] of Object.entries(bundle)) {
                const hash = this.createChunkHash(chunk);
                if (!seen.has(hash)) {
                    seen.add(hash);
                    deduped[fileName] = chunk;
                }
            }

            // Update bundle in place
            Object.keys(bundle).forEach(key => delete bundle[key]);
            Object.assign(bundle, deduped);
        },

        compressStage(bundle) {
            // Compress chunks (simplified)
            for (const chunk of Object.values(bundle)) {
                if (chunk.type === 'chunk' && chunk.code) {
                    // Basic compression - in practice, you'd use a proper minifier
                    chunk.code = chunk.code
                        .replace(/\/\*[\s\S]*?\*\//g, '') // Remove comments
                        .replace(/\s+/g, ' ') // Collapse whitespace
                        .trim();
                }
            }
        },

        createChunkHash(chunk) {
            const crypto = require('crypto');
            const content = chunk.code || chunk.source || '';
            return crypto.createHash('md5').update(content).digest('hex');
        }
    };
}

// ===== ROLLUP CONFIGURATION WITH ECOSYSTEM INTEGRATION =====

// rollup.config.js - Complete ecosystem example
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import json from '@rollup/plugin-json';
import { terser } from 'rollup-plugin-terser';
import alias from '@rollup/plugin-alias';

// Import custom plugins
import aliasResolverPlugin from './plugins/alias-resolver-plugin.js';
import virtualModulesPlugin from './plugins/virtual-modules-plugin.js';
import cssProcessorPlugin from './plugins/css-processor-plugin.js';
import environmentConfigPlugin from './plugins/environment-config-plugin.js';
import dependencyManagerPlugin from './plugins/dependency-manager-plugin.js';
import configValidatorPlugin from './plugins/config-validator-plugin.js';
import optimizationPipelinePlugin from './plugins/optimization-pipeline-plugin.js';

// Virtual modules
const virtualModules = {
    'config': `
export const API_URL = __ENV_API_URL__;
export const VERSION = '__CURRENT_ENV__-v1.0.0';
`,
    'constants': `
export const APP_NAME = 'My App';
export const BUILD_DATE = new Date().toISOString();
`
};

export default {
    input: 'src/index.js',
    output: [
        {
            file: 'dist/bundle.esm.js',
            format: 'es',
            sourcemap: true
        },
        {
            file: 'dist/bundle.cjs.js',
            format: 'cjs',
            sourcemap: true
        },
        {
            file: 'dist/bundle.umd.js',
            format: 'umd',
            name: 'MyApp',
            sourcemap: true
        }
    ],

    plugins: [
        // Configuration validation
        configValidatorPlugin({
            requiredOptions: ['input'],
            optionValidators: {
                input: (value) => typeof value === 'string',
                output: (value) => Array.isArray(value) || typeof value === 'object'
            },
            strict: true
        }),

        // Dependency management
        dependencyManagerPlugin({
            dependencies: {
                'node-resolve': '^13.0.0',
                'typescript': '^8.0.0'
            },
            autoInstall: false
        }),

        // Environment configuration
        environmentConfigPlugin({
            environments: {
                development: {
                    API_URL: 'http://localhost:3000/api',
                    DEBUG: true
                },
                production: {
                    API_URL: 'https://api.myapp.com',
                    DEBUG: false
                },
                test: {
                    API_URL: 'http://test-api:3000/api',
                    DEBUG: true
                }
            }
        }),

        // Core plugins
        nodeResolve({
            browser: true,
            preferBuiltins: false
        }),
        commonjs(),
        typescript(),
        json(),

        // Alias resolution
        alias({
            entries: [
                { find: '@', replacement: './src' },
                { find: '@utils', replacement: './src/utils' },
                { find: '@components', replacement: './src/components' }
            ]
        }),

        // Custom alias resolver (works with node-resolve)
        aliasResolverPlugin({
            alias: {
                'react': 'preact/compat',
                'react-dom': 'preact/compat'
            }
        }),

        // Virtual modules
        virtualModulesPlugin(virtualModules),

        // CSS processing
        cssProcessorPlugin({
            inject: process.env.NODE_ENV === 'development',
            minimize: process.env.NODE_ENV === 'production',
            plugins: [
                require('autoprefixer'),
                require('cssnano')({
                    preset: 'default'
                })
            ]
        }),

        // Optimization pipeline
        optimizationPipelinePlugin({
            stages: ['dedupe', 'optimize-imports', 'compress'],
            parallel: true
        }),

        // Production optimizations
        process.env.NODE_ENV === 'production' && terser({
            format: {
                comments: /^!/,
                ascii_only: true
            },
            compress: {
                drop_console: true,
                drop_debugger: true,
                pure_funcs: ['console.log', 'console.info'],
                passes: 2
            },
            mangle: {
                properties: {
                    regex: /^_/
                }
            }
        })
    ].filter(Boolean)
};

// Export for use in other files
export {
    aliasResolverPlugin,
    virtualModulesPlugin,
    cssProcessorPlugin,
    environmentConfigPlugin,
    dependencyManagerPlugin,
    configValidatorPlugin,
    optimizationPipelinePlugin
};