Plugin System

PawaJS features a powerful and flexible plugin system that allows you to extend its core functionality. You can introduce new custom directives, hook into the component lifecycle, and tap into the rendering pipeline.

Registering a Plugin

Plugins are registered by calling the PluginSystem function. This should be done once when your application starts. The function accepts one or more functions, each returning a plugin object.

javascript
                
import { PluginSystem, pawaStartApp } from "pawajs";
import { myCustomPlugin } from "./plugins/my-plugin.js";

// Register plugins before starting the app
PluginSystem(myCustomPlugin);

pawaStartApp(document.getElementById('app'));
             
            

Plugin Object Structure

A plugin is a function that returns an object with specific keys to hook into different parts of PawaJS.

javascript
                
export const myCustomPlugin = () => {
    return {
        attribute: { /* ... */ },
        component: { /* ... */ },
        renderSystem: { /* ... */ }
    };
};
             
            

1. Attribute Plugins

This is the most common use case: creating new custom directives. You can define attributes that trigger custom logic.

Example: A 'log-on-click' Directive

Let's create a simple plugin that adds a log-on-click directive to log a message when an element is clicked.

javascript
                
export const loggerPlugin = () => {
    return {
        attribute: {
            register: [
                {
                    // The exact attribute name
                    fullName: 'log-on-click',
                    
                    // The function to execute
                    plugin: (el, attr, stateContext) => {
                        const message = attr.value || 'Element clicked';
                        el.addEventListener('click', () => {
                            console.log(message, el);
                        });
                    }
                }
            ]
        }
    };
};
                 
            

You can then use it in your HTML:

html
                
<button log-on-click="Hello from my custom directive!">Log Message</button>
                 
            

Configuration Options

  • fullName: The exact name of the attribute (e.g., 'my-directive').
  • startsWith: A prefix for a group of directives (e.g., 'my-dir:'). The plugin will run for any attribute starting with this prefix.
  • plugin(el, attr, stateContext): The core logic. It receives the PawaElement, the attribute object {name, value}, and the component's state context.
  • mode: Can be 'client', 'server', or null (default, runs on both). Restricts where the plugin executes.
  • dependency: An array of other attribute names that this plugin depends on.

2. Component Hooks

Hook into the lifecycle of every component rendered by PawaJS.

  • beforeCall(stateContext, app): Runs right before a component function is executed. Useful for preparing context or logging.
  • afterCall(stateContext, el): Runs after a component has rendered its HTML string and the element is available. Useful for post-processing.
javascript
                
export const componentLoggerPlugin = () => {
    return {
        component: {
            beforeCall: (stateContext, app) => {
                console.log(`Component "${stateContext.component.name}" is about to render.`);
            },
            afterCall: (stateContext, el) => {
                console.log(`Component "${stateContext.component.name}" has rendered.`, el);
            }
        }
    };
};
             
            

3. Render System Hooks

For deeper integration, you can hook into the main rendering function that processes every element.

  • beforePawa(el, context): Runs before an HTMLElement is upgraded to a PawaElement.
  • afterPawa(el): Runs immediately after the element has been upgraded to a PawaElement.
  • beforeChildRender(el): Runs on a PawaElement just before its children are processed.
javascript
                
export const renderTrackerPlugin = () => {
    return {
        renderSystem: {
            afterPawa: (pawaElement) => {
                // Add a custom property to every processed element
                pawaElement._processedByPlugin = true;
            }
        }
    };
};