eleva

Plugin System

Version: 1.0.0 This guide covers creating, installing, and using plugins to extend Eleva’s functionality.

The Plugin System provides a powerful way to extend the framework’s functionality. Plugins can add new features, modify existing behavior, or integrate with external libraries.


Plugin Structure

A plugin in Eleva is an object with three required properties:

const MyPlugin = {
  name: "myPlugin",       // Unique identifier for the plugin
  version: "1.0.0",       // Semantic version string
  install(eleva, options) {
    // Plugin installation logic
  },
};
Property Type Description
name string Unique identifier for the plugin
version string Semantic version (e.g., “1.0.0”)
install function Receives Eleva instance and options

Installing Plugins

Plugins are installed using the use method:

const app = new Eleva("myApp");
app.use(MyPlugin, { /* optional configuration */ });

The use method:


Plugin Capabilities

1. Extend the Eleva Instance

install(eleva) {
  eleva.newMethod = () => { /* ... */ };
}

2. Add Component Features

install(eleva) {
  eleva.component("enhanced-component", {
    template: (ctx) => `...`,
    setup: (ctx) => ({ /* ... */ })
  });
}

3. Modify Component Behavior

install(eleva) {
  const originalMount = eleva.mount;
  eleva.mount = function(container, compName, props) {
    // Add pre-mount logic
    const result = originalMount.call(this, container, compName, props);
    // Add post-mount logic
    return result;
  };
}

4. Add Global State or Services

install(eleva) {
  eleva.services = {
    api: new ApiService(),
    storage: new StorageService()
  };
}

Plugin Development Best Practices

1. Naming Conventions

2. Error Handling

3. Documentation

4. Performance


Example Plugin: Logger

Here’s a complete example of a custom plugin:

const Logger = {
  name: "logger",
  version: "1.0.0",
  install(eleva, options = {}) {
    const { level = "info" } = options;

    // Add logging methods to Eleva instance
    eleva.log = {
      info: (msg) => console.log(`[INFO] ${msg}`),
      warn: (msg) => console.warn(`[WARN] ${msg}`),
      error: (msg) => console.error(`[ERROR] ${msg}`),
    };

    // Enhance component mounting with logging
    const originalMount = eleva.mount;
    eleva.mount = async function(container, compName, props) {
      eleva.log.info(`Mounting component: ${compName}`);
      const result = await originalMount.call(this, container, compName, props);
      eleva.log.info(`Component mounted: ${compName}`);
      return result;
    };
  },
};

// Usage
const app = new Eleva("myApp");
app.use(Logger, { level: "debug" });

Plugin Lifecycle

1. Installation

2. Runtime

3. Cleanup


TypeScript Support

Eleva provides TypeScript declarations for plugin development:

interface ElevaPlugin {
  name: string;
  version: string;
  install(eleva: Eleva, options?: Record<string, any>): void;
}

This ensures type safety when developing plugins in TypeScript.


Built-in Plugins

Eleva comes with three powerful built-in plugins:

Plugin Purpose Size Docs
Attr ARIA, data-*, boolean attributes ~2.4KB View →
Router Client-side routing & guards ~15KB View →
Store Global state management ~6KB View →

Attr Plugin

Advanced attribute handling with ARIA support:

import { Attr } from 'eleva/plugins';

app.use(Attr, {
  enableAria: true,
  enableData: true,
  enableBoolean: true,
  enableDynamic: true
});

Features:

Full Attr Documentation →

Router Plugin

Client-side routing with reactive state:

import { Router } from 'eleva/plugins';

const router = app.use(Router, {
  mount: '#app',
  mode: 'hash',
  routes: [
    { path: '/', component: HomePage },
    { path: '/about', component: AboutPage },
    { path: '/users/:id', component: UserPage }
  ]
});

await router.start();

Features:

Full Router Documentation →

Store Plugin

Centralized state management:

import { Store } from 'eleva/plugins';

app.use(Store, {
  state: { count: 0, user: null },
  actions: {
    increment: (state) => state.count.value++,
    setUser: (state, user) => state.user.value = user
  },
  persist: { key: "app-state", storage: "localStorage" }
});

Features:

Full Store Documentation →

Plugin Installation

import Eleva from 'eleva';
import { Attr, Router, Store } from 'eleva/plugins';

const app = new Eleva("MyApp");

// Install plugins
app.use(Attr);
app.use(Store, { state: {} });
app.use(Router, { routes: [] });

Bundle Sizes

Plugin Minified Gzipped
Core ~6KB ~2.3KB
Attr ~2.4KB ~1KB
Router ~15KB ~5KB
Store ~6KB ~2KB

Creating a Custom Plugin

Step 1: Define the Plugin

// my-analytics-plugin.js
export const Analytics = {
  name: "analytics",
  version: "1.0.0",
  install(eleva, options = {}) {
    const { trackingId, debug = false } = options;

    // Initialize analytics
    if (debug) {
      console.log(`Analytics initialized with ID: ${trackingId}`);
    }

    // Add tracking methods
    eleva.analytics = {
      track(event, data) {
        if (debug) {
          console.log(`[Analytics] ${event}:`, data);
        }
        // Send to analytics service
      },
      page(path) {
        this.track('pageview', { path });
      }
    };

    // Auto-track component mounts
    const originalMount = eleva.mount;
    eleva.mount = async function(container, compName, props) {
      const result = await originalMount.call(this, container, compName, props);
      eleva.analytics.track('component_mount', { component: compName });
      return result;
    };
  }
};

Step 2: Use the Plugin

import Eleva from 'eleva';
import { Analytics } from './my-analytics-plugin.js';

const app = new Eleva("MyApp");
app.use(Analytics, {
  trackingId: 'UA-XXXXX-Y',
  debug: true
});

// Now available throughout your app
app.analytics.track('button_click', { button: 'signup' });

Step 3: Publish (Optional)

// package.json
{
  "name": "eleva-plugin-analytics",
  "version": "1.0.0",
  "main": "dist/index.js",
  "peerDependencies": {
    "eleva": "^1.0.0"
  }
}

Plugin Patterns

Extending Setup Context

install(eleva) {
  const originalMount = eleva.mount.bind(eleva);

  eleva.mount = async (container, compName, props) => {
    // Inject custom utilities into setup context
    const enhancedProps = {
      ...props,
      myUtility: () => { /* ... */ }
    };
    return originalMount(container, compName, enhancedProps);
  };
}

Adding Lifecycle Hooks

install(eleva) {
  eleva.onComponentMount = (callback) => {
    const originalMount = eleva.mount.bind(eleva);
    eleva.mount = async (...args) => {
      const result = await originalMount(...args);
      callback(result);
      return result;
    };
  };
}

Global Event Bus

install(eleva) {
  const events = new Map();

  eleva.bus = {
    on(event, handler) {
      if (!events.has(event)) events.set(event, []);
      events.get(event).push(handler);
      return () => this.off(event, handler);
    },
    off(event, handler) {
      const handlers = events.get(event);
      if (handlers) {
        const index = handlers.indexOf(handler);
        if (index > -1) handlers.splice(index, 1);
      }
    },
    emit(event, data) {
      const handlers = events.get(event);
      if (handlers) handlers.forEach(h => h(data));
    }
  };
}

Next Steps


← Architecture Back to Main Docs Best Practices →